Detecting decreasing functions

Doug Meade's picture

In my work developing Maplets for Calculus, there are many instances when I want to determine that a function is monotone (decreasing or increasing or non-decreasing or non-increasing) on an interval. If I can do one of these, I can do them all. So, let's focus on decreasing.

I have no problem assuming f is continuous and differentiable on the interval. The interval could be unbounded, and I am not terribly concerned about endpoints (at least now).

Given a function f, how would you use Maple to determine that f is decreasing on an interval (possibly unbounded)?

The basic test I started with is (with argument testing stripped out):

IsDecr := proc( F, a, b )
  local b2, R;
  R:=is( diff(F,x), negative ) assuming x>a, x<b;
  if R=FAIL then
    b2 := `if`(b=infinity,a+100,b);
    R:=convert( map( is, [seq(eval(F,x=k), k=a..b2)], negative ), `and` );
  end if;
  return R
end proc:

The secondary test is a weak test that is used because the underlying function comes from a sequence or series (hence restricting the tests to integers). It is rarely used.

This test has been pretty effective. But, this morning I found an example on which my IsDecr - and anything else I have tried - fails to work.

f := arctan(x)/(1+x^2);
                                  arctan(x)
                                  ---------
                                        2  
                                   1 + x   
debug( IsDecr );
                                   IsDecr
IsDecr( f, 1, infinity );
{--> enter IsDecr, args = `/`(`*`(arctan(x)), `*`(`+`(1, `*`(`^`(x, 2))))), 1, infinity
                                    false
<-- exit IsDecr (now at top level) = false}
                                    false

Since Maple responded with a definite false to the initial query, this example never got to the weak test.

Additional attempts for this specific example have not been very productive.

df := simplify( diff( f, x ) );
                              -1 + 2 arctan(x) x
                            - ------------------
                                          2     
                                  /     2\      
                                  \1 + x /      
plot( [f,df], x=0..5 );
solve( df<0, x );
solve( df>0, x );
solve( df=0, x );
                        tan(RootOf(2 _Z tan(_Z) - 1))
allvalues( % );
                 tan(RootOf(2 _Z tan(_Z) - 1, 0.6532711871))

I could construct code to work with the fact that there is only one root to determine the sign of df on either side. But, doing this in general will be rather involved.

I have looked at the Student[Calculus1] package, with some interesting results:

Student[Calculus1]:-CriticalPoints(f);
                                     []
Student[Calculus1]:-CriticalPoints(f, x);
                                     []
Student[Calculus1]:-CriticalPoints(f, x=0..1);
                                     []
Student[Calculus1]:-CriticalPoints(f, x=0..1, numeric);
                               [0.7653789267]

What is most interesting about this is that the result is so different from the one obtained earlier by solving df=0. Comparing these results shows that the Student[Calculus1] result is reasonable:

eval( df, x=0.765378 );
                                            -7
                              8.371333166 10  
eval( df, x=0.653271 );
                                0.1198346374

To close, I will point out that fsolve does confirm the output from CriticalPoints:

fsolve( df=0, x=0..10 );
                                0.7653789267

The worksheet containing all of this work has been posted to MaplePrimes; use the following links to access it:
View 178_IsDecr.mw on MapleNet or Download 178_IsDecr.mw
View file details

I hope someone has some experience with this and is willing to share with the community.

Doug

Comments

JacquesC's picture

Misinterpretation of solve's result

If you had done solve({df=0},{x});, you would have gotten {x=tan(RootOf(2*_Z*tan(_Z) - 1, 0.6532711871))} as a result, which completely agrees with your result:

 tt := RootOf(2*_Z*tan(_Z) - 1, 0.6532711871): evalf(tan(tt));
                             0.7653789267

It took me a little while to figure this out too. But Maple is correct here (inasmuch as Student[Calculus1]:-CriticalPoints returning an empty result can be considered ``correct'').

Robert Israel's picture

Maximize the derivative

You could try a numerical global optimization to see if the derivative is ever positive. With gmax in my Maple Advisor Database:

> Q:= arctan(x)/(1+x^2):
  gmax(diff(Q,x), x=1 .. infinity, 'x0');

-0.

> x0;

{infinity, .1889785610e12}

You could also try Optimization[Maximize](..., method=branchandbound), but this requires a finite interval.
Well, let's try transforming to a finite interval.

> Q1:= eval(Q, x = tan(t)):
  Optimization[Maximize](diff(Q1,t), t=Pi/4 .. Pi/2,
    method=branchandbound);

[-.102712384246536857e-13, [t = 1.57079632679490012]]<br />

Note that, due to roundoff error, the result could quite easily have ended up slightly positive rather than slightly negative. Unfortunately, it's hard to tell just how big a value should be considered as "really" positive.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
}