#if !defined HAVE_CONVEX_H__
#define      HAVE_CONVEX_H__


#include "fxttypes.h"


template <typename Type>
long is_convex(Type *f, ulong n)
// Return
//   +val for convex sequence (first rising, then falling)
//   -val for concave sequence (first falling, then rising)
//   else 0
// val is the (second) index of the first pair at the point
// where the ordering changes;  val>=n iff seq. is monotone.
// Note: a constant sequence is considered any of rising/falling
{
    if ( 1>=n )  return +1;

    ulong k = 1;
    for (k=1; k<n; ++k)  // skip constant start
    {
        if ( f[k] != f[k-1] )  break;
    }

    if ( k==n )  return  +n;  // constant is considered convex here

    int s = ( f[k] > f[k-1] ? +1 : -1 );

    if ( s>0 ) // was: ascending
    {
        // scan for strictly descending pair:
        for (  ; k<n; ++k)  if ( f[k] < f[k-1] )  break;
        s = +k;
    }
    else // was: descending
    {
        // scan for strictly ascending pair:
        for (  ; k<n; ++k)  if ( f[k] > f[k-1] )  break;
        s = -k;
    }

    if ( k==n )  return s;  // sequence is monotone

    // check that the ordering does not change again:
    if ( s>0 ) // was: ascending --> descending
    {
        // scan for strictly ascending pair:
        for (  ; k<n; ++k)  if ( f[k] > f[k-1] )  return 0;
    }
    else // was: descending
    {
        // scan for strictly descending pair:
        for (  ; k<n; ++k)  if ( f[k] < f[k-1] )  return 0;
    }

    return  s;
}
// -------------------------



template <typename Type>
long is_strictly_convex(Type *f, ulong n)
// Return
//   +val for strictly convex sequence
//        (i.e. first strictly rising, then strictly falling)
//   -val for strictly concave sequence
//        (i.e. first strictly falling, then strictly rising)
//   else 0
// val is the (second) index of the first pair at the point
// where the ordering changes;  val>=n iff seq. is strictly monotone.
{
    if ( 1>=n )  return +1;

    ulong k = 1;
    if ( f[k] == f[k-1] )  return 0;

    int s = ( f[k] > f[k-1] ? +1 : -1 );

    if ( s>0 ) // was: ascending
    {
        // scan for descending pair:
        for (  ; k<n; ++k)  if ( f[k] <= f[k-1] )  break;
        s = +k;
    }
    else // was: descending
    {
        // scan for ascending pair:
        for (  ; k<n; ++k)  if ( f[k] >= f[k-1] )  break;
        s = -k;
    }

    if ( k==n )  return s;  // sequence is monotone
    else  if ( f[k] == f[k-1] )  return 0;

    // check that the ordering does not change again:
    if ( s>0 ) // was: ascending --> descending
    {
        // scan for ascending pair:
        for (  ; k<n; ++k)  if ( f[k] >= f[k-1] )  return 0;
    }
    else // was: descending
    {
        // scan for descending pair:
        for (  ; k<n; ++k)  if ( f[k] <= f[k-1] )  return 0;
    }

    return  s;
}
// -------------------------


#endif // !defined HAVE_CONVEX_H__
