How do I make Mathematica filter results based on constraints
October 7, 2011 12:40 PM   Subscribe

I'm a relative newbie using Mathematica and I can't figure out how to filter results from NSolve (or Solve) based on some constraints, like making it only show positive solutions.

For instance, if I enter NSolve[x^2 - 1 == 0, x] I get the result {{x -> -1.}, {x -> 1.}}. I'd like to add constraints on what values x can take, like only making it positive (hence returning {{x->1.}}).

This would be especially useful if I could do it for things like trigonometric equations that have infinite solutions, and only make it return the one solution in a given range. I figured that there would be some sort of pattern or filter you can apply to the resulting list, but I can't figure out how to use the functions (like Select) I can find.

Any help would be highly appreciated!
posted by gkhan to Computers & Internet (8 answers total) 1 user marked this as a favorite
NSolve returns a list of substitution rules, and Select works on lists of numbers. To apply the substitution rules, use "/." So, for example
list = x /. NSolve[x^3 + 2 x == 1, x]
which returns
{-0.226699 - 1.46771 I, -0.226699 + 1.46771 I, 0.453398}
and then you can use
Select[list, # \[Element] Reals &]
which returns

Is this the kind of thing you're looking for?
posted by zeptoweasel at 1:00 PM on October 7, 2011

...Uh, I didn't mean to imply Select only works on lists of numbers.
posted by zeptoweasel at 1:04 PM on October 7, 2011

Response by poster: Yes, that is kinda what I'm looking for, but can I filter before applying the substitution rule? I.e. filter {{x->-1},{x->1}} directly, not {{-1},{1}}. The reason this came up in this case was that I wanted to do a version of this:

x + 4 /. NSolve[x^2 - 1 == 0, x]

but only have it replacing the positive solution/solutions of NSolve. I guess I can apply the substitution rule again after using your method, but is there a more elegant solution?
posted by gkhan at 1:10 PM on October 7, 2011

Best answer: Hmm, here's a one-liner, although I wouldn't call it elegant:
x + 4 /. x -> Select[x /. NSolve[x^2 - 1 == 0, x], # > 0 &]
posted by zeptoweasel at 1:16 PM on October 7, 2011

Response by poster: Ok, thanks! That'll work out just fine. So nice to ask things here, you get such prompt and helpful answers.
posted by gkhan at 1:22 PM on October 7, 2011

You can also filter by attaching bounds to your equation inside the NSolve, using &&

For example: Suppose you wanted the roots of x^4 + x^3 + 2 x == 1.

NSolve[x^4 + x^3 + 2 x == 1, x] returns {{x -> -1.79431}, {x -> 0.177611- 1.11253 I}, {x ->
0.177611+ 1.11253 I}, {x -> 0.439087}}.

To get the real roots, NSolve has an option of Reals:

NSolve[x^4 + x^3 + 2 x == 1, x, Reals] gives {{x -> -1.79431}, {x -> 0.439087}}.

To get the positive ones:

NSolve[x^4 + x^3 + 2 x == 1 && x >= 0, x, Reals] gives {{x -> 0.439087}}

in fact, you don't need the Reals.

In[67]:= NSolve[x^4 + x^3 + 2 x == 1 && x >= 0, x]

Out[67]= {{x -> 0.439087}}

To get the ones between -3 and 0, try:

In[60]:= NSolve[x^4 + x^3 + 2 x == 1 && -3 <>
Out[60]= {{x -> -1.79431}}

If you are not used to spending some quality time with the help browser, I encourage you to do so. It's really the only way.
posted by leahwrenn at 2:24 PM on October 7, 2011 [1 favorite]

Best answer: Drat. I didn't notice I needed to be careful about the ≤ signs. Ugh HTML.

The last input should have been NSolve[x^4 + x^3 + 2 x == 1 && -3 ≤ x ≤ 0, x]

Oh, and

In[69]:= NSolve[Cos[x] == 0 && 3 Pi ≤ x ≤ 6 Pi, x]

Out[69]= {{x -> 10.9956}, {x -> 14.1372}, {x -> 17.2788}}

In[70]:= Solve[Cos[x] == 0 && 3 Pi ≤ x ≤ 6 Pi, x]

Out[70]= {{x -> (7 \[Pi])/2}, {x -> (9 \[Pi])/2}, {x -> (11 \[Pi])/2}}

So it works nicely on your trigonometric equations, and this is not restricted to NSolve.
posted by leahwrenn at 2:29 PM on October 7, 2011

leahwrenn's bounding trick is quite nice! I might have known that years ago, but have long since forgotten. It's going back in the mathematica toolbag.

If you're working with simple expressions, there's no reason not to use NSolve. However, for sufficiently complicated polynomial expressions, you may encounter buggy behavior (at least in Mathematica 7). NSolve also gives up on transcendental equations:

In[1]:= NSolve[Exp[-x] == Sin[x], x]
Solve::tdep: The equations appear to involve the variables to be solved for in an essentially non-algebraic way.

This is because NSolve attempts to find all possible solutions, and that's hard with transcendental equations. In some cases, it is better to try to use FindRoot, which only searches for a single root.

In[2]:= FindRoot[Exp[-x] == Sin[x], {x, 3}]
Out[2]= {x -> 3.09636}

If you care about all possible roots, or if you have no clue where the roots of the equation may be, FindRoot is a terrible choice. If you only care about a single root and have a rough idea* of where it might be, though, FindRoot will find it quickly.

Added bonus: NSolve has to spend time to compute all roots to the equation (which can be computationally expensive). FindRoot does a pretty fast search looking for only a single root, so is quick for complex equations.

*It can't be too rough.... You'll get bounced around for
In[3]:=FindRoot[Exp[x] == Sin[x], {x, 1}] (note the sign change in Exp)
Out[3]={x -> -6.28131}
posted by bessel functions seem unnecessarily complicated at 2:58 PM on October 7, 2011

« Older Microfilm Digitization: What's the Better Machine?   |   Erectile Dysfunction and Emotions Newer »
This thread is closed to new comments.