Solving a differential equation in Mathematica - wolfram-mathematica

I have a syntax problem solving a differential equation in Mathematica (10th version).
The input for the equation I need to solve is as follows:
solv = DSolve[{ a*u''[y] - b*u[y] == d, u'[0] == 0, u[1] == 0}, u, {y, -1, 1}]
Which after using ExpToTrig and FullSimplify I get the answer I am looking for:
(d (-1 + Cosh[(Sqrt[b] y)/Sqrt[a]] Sech[Sqrt[b]/Sqrt[a]]))/b
However, my problem comes when I want to place more coefficients in the equation. For example:
solv = DSolve[{ a* u''[y] - b* c* u[y] == d, u'[0] == 0, u[1] == 0}, u, {y, -1, 1}]
This time, I get for:
FullSimplify[ExpToTrig[Evaluate[u[y] /. solv]]]
The next answer:
(d (1 + E^((2 Sqrt[b] Sqrt[c])/Sqrt[a]) - E^(-((Sqrt[b] Sqrt[c] (-1 + y))/Sqrt[a])) - E^((Sqrt[b] Sqrt[c] (1 + y))/Sqrt[a])) (-1 + Tanh[(Sqrt[b] Sqrt[c])/Sqrt[a]]))/(2 b c)
Instead, when I merge b and c (substitute: bc=b*c):
solv = DSolve[{ a*u''[y] - bc*u[y] == d, u'[0] == 0, u[1] == 0}, u, {y, -1, 1}]
I get:
(d (-1 + Cosh[(Sqrt[bc] y)/Sqrt[a]] Sech[Sqrt[bc]/Sqrt[a]]))/bc
In my case I can't just substitute because there are too many equations and some of the parameters (coefficients) cancel.
Thanks!

Your issue is with FullSimplify. It deems the exp form more "simple" than the trig form so it is undoing what ExpToTrig is doing. Using just Simplify in its place will maintain the ExpToTrig conversion. My quick try below shows a comparison.

Related

transform equation with Mathematica

I'm try to use Mathematica to transform a couple of komplex equations, but I didn't get the right syntax.
Solve[{EI*w[x] == Piecewise[{{(x - a)^3, x >= a}, {0, x < a}}]*F*(1/6) +
ca*(x³)*(1/6) + cb*(x^2)*0.5 + cc*x + cd,
EI*w'[x] == Piecewise[{{(x - a)², x >= a}, {0, x < a}}]*F*0.5 + ca*(x^2)*0.5 + cb*x + cc,
EI*w''[x] == Piecewise[{{(x - a)^1, x >= a}, {0, x < a}}]*F + ca*x*0.5 + cb,
EI*w'''[x] == Piecewise[{{(x - a)^0, x >= a}, {0, x < a}}]*F + ca,
w[0] == -EIw'''[0]/ka, w[l] == EIw'''[0]/kb, w'[0] == 0, w'[l] == 0},
{ca, cb, cc, cd}]
Can someone give me a hint how to solve these equations with Mathematica.
Begin by cleaning up some typesetting issues.
We simplify this by looking only at the domain x>=a
Solve[{EI*w[x] == (x-a)^3*F*(1/6)+ca*(x^3)*(1/6)+cb*(x^2)*(1/2)+cc*x+cd,
EI*w'[x] == (x-a)^2*F*(1/2)+ca*(x^2)*(1/2)+cb*x+cc,
EI*w''[x] == (x-a)^1*F+ca*x*(1/2)+cb,
EI*w'''[x] == (x-a)^0*F+ca,
w[0] == -EI*w'''[0]/ka, w[1] == EI*w'''[0]/kb, w'[0] == 0, w'[1] == 0},
w[x], x]
Your second equation is just derivative of first equation and provides no additional information
In[1]:= D[(x-a)^3*F*(1/6)+ca*(x^3)*(1/6)+cb*(x^2)*(1/2)+cc*x+cd, x] ==
(x-a)^2*F*(1/2)+ca*(x^2)*(1/2)+cb*x+cc
Out[1]= True
Your third and fourth equations give information about ca
In[2]:= Simplify[D[(x-a)^1*F+ca*x*(1/2)+cb, x] == (x-a)^0*F+ca]
Out[2]= ca == 0
OR it seems more and more likely that this is the result of a typo in the equations from the original poster. Without more information from the original poster it isn't possible to decide whether this is correct or not. But the person should be able to look at the method used and get the solution needed.
Thus
w[x] == ((x-a)^3*F*(1/6)+cb*(x^2)*(1/2)+cc*x+cd)/EI
In[3]:= w'[x] == D[((x-a)^3*F*(1/6)+cb*(x^2)*(1/2)+cc*x+cd)/EI, x]
Out[3]= w'[x] == (cc+cb x+1/2 F (-a+x)^2)/EI
In[4]:= w'''[x] == D[((x-a)^3*F*(1/6)+cb*(x^2)*(1/2)+cc*x+cd)/EI, {x, 3}]
Out[4]= w'''[x] == F/EI
We already know ca, solve for the remaining three variables using the first three boundary conditions
In[5]:= Simplify[Solve[{((0-a)^3*F*(1/6)+cb*(0^2)*(1/2)+cc*0+cd)/EI == -EI*(F/EI)/ka,
((l-a)^3*F*(1/6)+cb*(l^2)*(1/2)+cc*l+cd)/EI == EI*(F/EI)/kb,
(cc+cb x+1/2 F (-a+0)^2)/EI == 0}, {cb, cc, cd}]]
Out[5]= {{cb -> (F (6 EI (ka+kb)+ka kb (3 a-l) l^2))/(3 ka kb l (l-2 x)),
cc -> -((F (3 a^2 ka kb l (l-2 x)+6 a ka kb l^2 x+
2 (6 EI (ka+kb)-ka kb l^3) x))/(6 ka kb l (l-2 x))),
cd -> 1/6 F (a^3-(6 EI)/ka)}}
Look at the final boundary condition
In[7]:= Simplify[(cc+cb x+1/2 F (-a+l)^2)/EI == 0 /. Out[5]]
Out[7]= {(F l (-2 a+l))/EI == 0}
Check every step of this carefully and verify that no errors were made.
Then go back and see if you can use these same methods for the domain x < a

NDSolve inside NDSolve in Mathematica

I need to use NDSolve which in turn uses the solution from another ODE as function in terms of output from another NDSolve.
If I use the exact solution from the first differential equation inside the NDSolve, it's OK. But when I use the same solution in the form of function (which uses InterpolatingFunction) it does not work.
I believe, it's got to do with the structure of NDSolve output. Could anyone please enlighten me on this. Will be of great help!
The code is:
feq = 2 V alpha fip F''[fi] - (V^2 - (V^2 + sigma - 2 fi) (F'[fi])^2 + (F'[fi])^4
Frange[lo_, hi_] :=
Module[{fii, sol},
sol = NDSolve[{(feq == 0 /.fi -> fii), F[0] == 0}, F, {fii, lo, hi}]]
eqpois = fi''[x] == ne[x] - F[fi[x]]/.sol
NDSolve[{eqpois, fi'[0] == 0, fi[0] == 0}, fi, {x,0,1}]
Here in order to find F[phi], I need to solve the 1st diff eq that is feq, which is solved by NDSolve inside the function Frange[lo,hi]. The solution is then used inside the second equation eqpois, which has to be solved using NDSolve again. The problem comes up in the second NDSolve, which does not produce the result. If I use the analytical solution of F[phi] in eqopis, then there is no problem.
Example Problem
I have done a little experiment with this. Let's take an example of coupled ODEs
1st eqn : dg/dx = 2f(g) with initial condition g(0) = 1
The function f(y) is a solution from another ODE, say,
2nd eqn : df/dy = 2y with IC f(0) = 0
The solution of the 2nd ODE is f(y) = y^2 which when put into the the 1st ODE becomes
dg/dx = 2 g^2 and the final solution is g(x) = 1/(1-2x)
The issue:
When I use DSolve, it finds the answer correctly
In[39]:= s = DSolve[{f'[y] == 2 y, f[0] == 0}, f, y]
Out[39]= {{f -> Function[{y}, y^2]}}
In[40]:= ss = DSolve[{g'[x] == 2 (f[g[x]]/.First#s), g[0] == 1}, g, x]
Out[40]= {{g -> Function[{y}, 1/(1 - 2 x)]}}
The problem comes when I use NDSolve
In[41]:= s = NDSolve[{f'[y] == 2 y, f[0] == 0}, f, {y, 1, 5}]
Out[41]= {{f -> InterpolatingFunction[{{1., 5.}}, <>]}}
In[42]:= ss1 = NDSolve[{g'[x] == 2 (Evaluate[f[g[x]]/.First#s1]), g[0] == 1}, g, {x, 1, 2}]
Out[42]= {}
The erros are:
During evaluation of In[41]:= InterpolatingFunction::dmval: Input value {2.01726} lies outside the range of data in the interpolating function. Extrapolation will be used. >>
During evaluation of In[41]:= InterpolatingFunction::dmval: Input value {2.01726} lies outside the range of data in the interpolating function. Extrapolation will be used. >>
During evaluation of In[41]:= InterpolatingFunction::dmval: Input value {2.04914} lies outside the range of data in the interpolating function. Extrapolation will be used. >>
During evaluation of In[41]:= General::stop: Further output of InterpolatingFunction::dmval will be suppressed during this calculation. >>
During evaluation of In[41]:= NDSolve::ndsz: At y == 0.16666654771477857, step size is effectively zero; singularity or stiff system suspected. >>
During evaluation of In[41]:= NDSolve::ndsz: At y == 0.16666654771477857, step size is effectively zero; singularity or stiff system suspected. >>
Any help in this regard will be highly appreciated!
--- Madhurjya
I got your simple example to work with a little mod ..
f0 = First#First#DSolve[{f'[y] == 2 y, f[0] == 0}, f, y]
g0 = g /.
First#First#DSolve[{g'[x] == 2 (f[g[x]] /. f0), g[0] == 1}, g, x]
fn = f /. First#First#NDSolve[{f'[y] == 2 y, f[0] == 0}, f, {y, 0, 10}]
gn = g /.
First#First#
NDSolve[{g'[x] == 2 (fn[g[x]]), g[0] == 1}, g, {x, 0, 9/20}]
GraphicsRow[{
Plot[{g0#x, gn#x}, {x, 0, 9/20},
PlotStyle -> {{Thick, Black}, {Thin, Red, Dashed}}],
Plot[{f#x /. f0, fn#x}, {x, 0, 2},
PlotStyle -> {{Thick, Black}, {Thin, Red, Dashed}}]}]
note we need to ensure the y range in the first NDSolve is sufficient to cover the expected range of g from the second. That is where all those interpolation range errors come from.

How to solve a linear differential equation with a random coefficient in Mathematica

I have a differential system like
dx/dt = A x(t) + B y(t)
dy/dt = C x(t) + D y(t)
where A, B, C, and D are real constants. Now I need to explore the behavior of the system if A, instead of being a constant number, is a random number uniformly distributed between a given range. I just need to check qualitatively. I have no background on stochastic integrals, therefore I do not know if this is actually something related with the Ito integral (and this question https://mathematica.stackexchange.com/questions/3141/how-can-you-compute-it-integrals-with-mathematica) . In any case, I do not know how to solve this differential equation.
Any guidance is highly appreciated.
The standard way to solve your system is
FullSimplify[
DSolve[{y'[t] == a x[t] + b y[t], x'[t] == c x[t] + d y[t]}, {y, x}, t]]
Now, you should think WHAT do you want to explore when {a, b, c, d} are random parameters.
Edit
Perhaps you want something like this:
s = FullSimplify[
DSolve[{y'[t] == #[[1]] x[t] + #[[2]] y[t], x'[t] == #[[3]] x[t] + #[[4]] y[t],
x[0] == 1, y[0] == 1}, {y, x}, t]] & /# RandomReal[{-1, 1}, {30, 4}];
ParametricPlot[Evaluate[{x[t], y[t]} /. s[[All, 1]]], {t, 0, 1}]

Creating points while using Mathematica's Table Function

I'm trying to plot points that I've created in a table in mathematica but for some reason one component of my points seems to have double braces around it while the other only has one as below:
{{x},y},{{x1},y1}....{{xn},yn}
and list plot will not recognize these as points and will not plot them.
Here is my mathematica code:
Remove["Global`*"]
b = .1;
w = 1;
Period = 1;
tstep = 2 Pi/Period;
s = NDSolve[{x''[t] + b x'[t] - x[t] + x[t]^3 - .5 Cos[w t] == 0,
x'[0] == 0, x[0] == 0}, x[t], {t, 0, 1000}, MaxSteps -> Infinity];
x[t_] = x[t] /. s
data = Table[Evaluate[{x'[t], .5}], {t, 0, 1000, tstep}]
ListPlot[data]
I've also tried using the command
ListPlot[Flatten[Table[Evaluate[{x'[t], .5}], {t, 0, 1000, tstep}]]]
to no avail as well as
ListPlot[Table[Evaluate[{Flatten[x'[t]], .5}], {t, 0, 1000, tstep}]]]
How can I remove the {}?
You may try something along these lines:
Clear["Global`*"]
b = .1;
w = 1;
s = NDSolve[{x''[t] + b x'[t] - x[t] + x[t]^3 - .5 Cos[w t] == 0,
x'[0] == 0, x[0] == 0}, x[t], {t, 0, 1000}, MaxSteps -> Infinity];
xr[u_] := ((x[t] /. s[[1]]) /. t -> u)
Plot[(xr'[u]), {u, 0, 30}]
But I am not sure what are you trying to get from the {x'[t], .5} part
My colleagues are correct, but I think there is more that can be said. First, to your actual question. The output of NDSolve is a list of the form
{{x[t]->InterpolatingFunction[...]}, {x[t]->InterpolatingFunction[...]}, ...}
where the second and subsequent replacement rules are only there if more than one solution is present. I have never encountered a case using NDSolve where that is true, but it makes the answer consistent with Solve, where multiple solutions is not uncommon. Therefor, with only one solution, you have a double list, i.e.
{{x[t]->InterpolatingFunction[...]}}
As per Mr. Wizard, you can use First, or you can use Part, i.e.
NDSolve[ ... ][[ 1 ]]
which is my preferred method, although it is slightly more difficult to read and may obscure your intent. You should be aware that the InterpolatingFunction that NDSolve returns is a function, and it will accept variables directly. So, the variables on the left hand side of the declarations
x[t_] = x[t] /. s
and from Belisarius
xr[u_] := ((x[t] /. s[[1]]) /. t -> u)
are superfluous at best, and the second one requires the replacement to occur every time xr is used. Instead, you can declare
x = x[t] /. s
and then writing x[t] afterwards will return IntepolatingFunction[t], exactly like you want. Then, as Belisarius points out, you can use it, or its derivative, in Plot directly, instead of first building a table of values and feeding them into ListPlot.
Edit: when I first posted this, I didn't notice a quirk with NDSolve. If you explicitly solve for x[t] not x, then NDSolve returns InterpolatingFunction[...][t], but if you just solve for x you get what I posted. This quirk allows both the OP's and Belisarius's solutions to function, otherwise the replacement shouldn't occur.
It is most likely that x'[t] is returning something of the form {x_i}. Try replacing the data=Table... line with this
data = Table[Evaluate[{First[x'[t]], .5}], {t, 0, 1000, tstep}]
An alternative would be to do
data=data /. {{x_}, y_} :> {x, y};
which uses ReplaceAll (/.) to replace every occurrence of {{x_i},y_i} with {x_i,y_i}
Example:
There are arguably better ways to accomplish what you are doing, but that is not what you asked.
To remove the extra {} recognize this comes from the result of NDSolve, and therefore use:
s = First # NDSolve[{x''[t] + b x'[t] - x[t] + x[t]^3 - .5 Cos[w t] == 0,
x'[0] == 0, x[0] == 0}, x[t], {t, 0, 1000}, MaxSteps -> Infinity];

Mathematica: branch points for real roots of polynomial

I am doing a brute force search for "gradient extremals" on the following example function
fv[{x_, y_}] = ((y - (x/4)^2)^2 + 1/(4 (1 + (x - 1)^2)))/2;
This involves finding the following zeros
gecond = With[{g = D[fv[{x, y}], {{x, y}}], h = D[fv[{x, y}], {{x, y}, 2}]},
g.RotationMatrix[Pi/2].h.g == 0]
Which Reduce happily does for me:
geyvals = y /. Cases[List#ToRules#Reduce[gecond, {x, y}], {y -> _}];
geyvals is the three roots of a cubic polynomial, but the expression is a bit large to put here.
Now to my question: For different values of x, different numbers of these roots are real, and I would like to pick out the values of x where the solutions branch in order to piece together the gradient extremals along the valley floor (of fv). In the present case, since the polynomial is only cubic, I could probably do it by hand -- but I am looking for a simple way of having Mathematica do it for me?
Edit: To clarify: The gradient extremals stuff is just background -- and a simple way to set up a hard problem. I am not so interested in the specific solution to this problem as in a general hand-off way of spotting the branch points for polynomial roots. Have added an answer below with a working approach.
Edit 2: Since it seems that the actual problem is much more fun than root branching: rcollyer suggests using ContourPlot directly on gecond to get the gradient extremals. To make this complete we need to separate valleys and ridges, which is done by looking at the eigenvalue of the Hessian perpendicular to the gradient. Putting a check for "valleynes" in as a RegionFunction we are left with only the valley line:
valleycond = With[{
g = D[fv[{x, y}], {{x, y}}],
h = D[fv[{x, y}], {{x, y}, 2}]},
g.RotationMatrix[Pi/2].h.RotationMatrix[-Pi/2].g >= 0];
gbuf["gevalley"]=ContourPlot[gecond // Evaluate, {x, -2, 4}, {y, -.5, 1.2},
RegionFunction -> Function[{x, y}, Evaluate#valleycond],
PlotPoints -> 41];
Which gives just the valley floor line. Including some contours and the saddle point:
fvSaddlept = {x, y} /. First#Solve[Thread[D[fv[{x, y}], {{x, y}}] == {0, 0}]]
gbuf["contours"] = ContourPlot[fv[{x, y}],
{x, -2, 4}, {y, -.7, 1.5}, PlotRange -> {0, 1/2},
Contours -> fv#fvSaddlept (Range[6]/3 - .01),
PlotPoints -> 41, AspectRatio -> Automatic, ContourShading -> None];
gbuf["saddle"] = Graphics[{Red, Point[fvSaddlept]}];
Show[gbuf /# {"contours", "saddle", "gevalley"}]
We end up with a plot like this:
Not sure if this (belatedly) helps, but it seems you are interested in discriminant points, that is, where both polynomial and derivative (wrt y) vanish. You can solve this system for {x,y} and throw away complex solutions as below.
fv[{x_, y_}] = ((y - (x/4)^2)^2 + 1/(4 (1 + (x - 1)^2)))/2;
gecond = With[{g = D[fv[{x, y}], {{x, y}}],
h = D[fv[{x, y}], {{x, y}, 2}]}, g.RotationMatrix[Pi/2].h.g]
In[14]:= Cases[{x, y} /.
NSolve[{gecond, D[gecond, y]} == 0, {x, y}], {_Real, _Real}]
Out[14]= {{-0.0158768, -15.2464}, {1.05635, -0.963629}, {1.,
0.0625}, {1., 0.0625}}
If you only want to plot the result then use StreamPlot[] on the gradients:
grad = D[fv[{x, y}], {{x, y}}];
StreamPlot[grad, {x, -5, 5}, {y, -5, 5},
RegionFunction -> Function[{x, y}, fv[{x, y}] < 1],
StreamScale -> 1]
You may have to fiddle around with the plot's precision, StreamStyle, and the RegionFunction to get it perfect. Especially useful would be using the solution for the valley floor to seed StreamPoints programmatically.
Updated: see below.
I'd approach this first by visualizing the imaginary parts of the roots:
This tells you three things immediately: 1) the first root is always real, 2) the second two are the conjugate pairs, and 3) there is a small region near zero in which all three are real. Additionally, note that the exclusions only got rid of the singular point at x=0, and we can see why when we zoom in:
We can then use the EvalutionMonitor to generate the list of roots directly:
Map[Module[{f, fcn = #1},
f[x_] := Im[fcn];
Reap[Plot[f[x], {x, 0, 1.5},
Exclusions -> {True, f[x] == 1, f[x] == -1},
EvaluationMonitor :> Sow[{x, f[x]}][[2, 1]] //
SortBy[#, First] &];]
]&, geyvals]
(Note, the Part specification is a little odd, Reap returns a List of what is sown as the second item in a List, so this results in a nested list. Also, Plot doesn't sample the points in a straightforward manner, so SortBy is needed.) There may be a more elegant route to determine where the last two roots become complex, but since their imaginary parts are piecewise continuous, it just seemed easier to brute force it.
Edit: Since you've mentioned that you want an automatic method for generating where some of the roots become complex, I've been exploring what happens when you substitute in y -> p + I q. Now this assumes that x is real, but you've already done that in your solution. Specifically, I do the following
In[1] := poly = g.RotationMatrix[Pi/2].h.g /. {y -> p + I q} // ComplexExpand;
In[2] := {pr,pi} = poly /. Complex[a_, b_] :> a + z b & // CoefficientList[#, z] & //
Simplify[#, {x, p, q} \[Element] Reals]&;
where the second step allows me to isolate the real and imaginary parts of the equation and simplify them independent of each other. Doing this same thing with the generic 2D polynomial, f + d x + a x^2 + e y + 2 c x y + b y^2, but making both x and y complex; I noted that Im[poly] = Im[x] D[poly, Im[x]] + Im[y] D[poly,[y]], and this may hold for your equation, also. By making x real, the imaginary part of poly becomes q times some function of x, p, and q. So, setting q=0 always gives Im[poly] == 0. But, that does not tell us anything new. However, if we
In[3] := qvals = Cases[List#ToRules#RReduce[ pi == 0 && q != 0, {x,p,q}],
{q -> a_}:> a];
we get several formulas for q involving x and p. For some values of x and p, those formulas may be imaginary, and we can use Reduce to determine where Re[qvals] == 0. In other words, we want the "imaginary" part of y to be real and this can be accomplished by allowing q to be zero or purely imaginary. Plotting the region where Re[q]==0 and overlaying the gradient extremal lines via
With[{rngs = Sequence[{x,-2,2},{y,-10,10}]},
Show#{
RegionPlot[Evaluate[Thread[Re[qvals]==0]/.p-> y], rngs],
ContourPlot[g.RotationMatrix[Pi/2].h.g==0,rngs
ContourStyle -> {Darker#Red,Dashed}]}]
gives
which confirms the regions in the first two plots showing the 3 real roots.
Ended up trying myself since the goal really was to do it 'hands off'. I'll leave the question open for a good while to see if anybody finds a better way.
The code below uses bisection to bracket the points where CountRoots changes value. This works for my case (spotting the singularity at x=0 is pure luck):
In[214]:= findRootBranches[Function[x, Evaluate#geyvals[[1, 1]]], {-5, 5}]
Out[214]= {{{-5., -0.0158768}, 1}, {{-0.0158768, -5.96046*10^-9}, 3}, {{0., 0.}, 2}, {{5.96046*10^-9, 1.05635}, 3}, {{1.05635, 5.}, 1}}
Implementation:
Options[findRootBranches] = {
AccuracyGoal -> $MachinePrecision/2,
"SamplePoints" -> 100};
findRootBranches::usage =
"findRootBranches[f,{x0,x1}]: Find the the points in [x0,x1] \
where the number of real roots of a polynomial changes.
Returns list of {<interval>,<root count>} pairs.
f: Real -> Polynomial as pure function, e.g f=Function[x,#^2-x&]." ;
findRootBranches[f_, {xa_, xb_}, OptionsPattern[]] := Module[
{bisect, y, rootCount, acc = 10^-OptionValue[AccuracyGoal]},
rootCount[x_] := {x, CountRoots[f[x][y], y]};
(* Define a ecursive bisector w/ automatic subdivision *)
bisect[{{x1_, n1_}, {x2_, n2_}} /; Abs[x1 - x2] > acc] :=
Module[{x3, n3},
{x3, n3} = rootCount[(x1 + x2)/2];
Which[
n1 == n3, bisect[{{x3, n3}, {x2, n2}}],
n2 == n3, bisect[{{x1, n1}, {x3, n3}}],
True, {bisect[{{x1, n1}, {x3, n3}}],
bisect[{{x3, n3}, {x2, n2}}]}]];
(* Find initial brackets and bisect *)
Module[{xn, samplepoints, brackets},
samplepoints = N#With[{sp = OptionValue["SamplePoints"]},
If[NumberQ[sp], xa + (xb - xa) Range[0, sp]/sp, Union[{xa, xb}, sp]]];
(* Start by counting roots at initial sample points *)
xn = rootCount /# samplepoints;
(* Then, identify and refine the brackets *)
brackets = Flatten[bisect /#
Cases[Partition[xn, 2, 1], {{_, a_}, {_, b_}} /; a != b]];
(* Reinclude the endpoints and partition into same-rootcount segments: *)
With[{allpts = Join[{First#xn},
Flatten[brackets /. bisect -> List, 2], {Last#xn}]},
{#1, Last[#2]} & ### Transpose /# Partition[allpts, 2]
]]]

Resources