#if !defined HAVE_CONVEX_H__
#define      HAVE_CONVEX_H__
// This file is part of the FXT library.
// Copyright (C) 2010, 2011 Joerg Arndt
// License: GNU General Public License version 3 or later,
// see the file COPYING.txt in the main directory.


#include "fxttypes.h"


template <typename Type>
ulong test_strictly_convex(Type *f, ulong n)
// Return index of maximum for strictly convex sequence,
//   otherwise return 0
{
    if ( n<=2 )  return 0;

    // the following two lines make sure the searches below stop:
    if ( f[0] >= f[1] ) return 0;
    if ( f[n-2] <= f[n-1] ) return 0;

    ulong i = 0;
    do  { ++i; }  while ( f[i-1] < f[i] );
    --i;
    // i is second index of last rising pair from start

    ulong j = n - 1;
    do  { --j; }  while ( f[j] > f[j+1] );
    ++j;
    // j is first index of last falling pair from end (going backwards)

    if ( i!=j )  return 0;
    return i;
}
// -------------------------

template <typename Type>
ulong test_strictly_concave(Type *f, ulong n)
// Return index of minimum for strictly concave sequence,
//   otherwise return 0
{
    if ( n<=2 )  return 0;

    // the following two lines make sure the searches below stop:
    if ( f[0] <= f[1] ) return 0;
    if ( f[n-2] >= f[n-1] ) return 0;

    ulong i = 0;
    do  { ++i; }  while ( f[i-1] > f[i] );
    --i;
    // i is second index of last falling pair from start

    ulong j = n - 1;
    do  { --j; }  while ( f[j] < f[j+1] );
    ++j;
    // j is first index of last rising pair from end (going backwards)

    if ( i!=j )  return 0;
    return i;
}
// -------------------------


template <typename Type>
ulong last_weak_rise_idx(Type *f, ulong n)
// Return last index of maximal weakly rising prefix of f[].
{
    if ( n<=1 )  return 0;
    ulong k = 0;
    do
    {
        if ( f[k] > f[k+1] )  break;
    }
    while ( ++k < n );
    k -= (k==n);
    return k;
}
// -------------------------

template <typename Type>
ulong last_weak_fall_idx(Type *f, ulong n)
// Return last index of maximal weakly falling prefix of f[].
{
    if ( n<=1 )  return 0;
    ulong k = 0;
    do
    {
        if ( f[k] < f[k+1] )  break;
    }
    while ( ++k < n );
    k -= (k==n);
    return k;
}
// -------------------------


template <typename Type>
bool is_weakly_convex(Type *f, ulong n)
// Return whether sequence is weakly convex
{
    if ( n<=2 )  return true;

    const ulong rl = last_weak_rise_idx(f, n);
    // if weakly convex ==> rl is a maximum
    const ulong ft = last_weak_fall_idx(f+rl, n-rl);
    const ulong fl = rl + ft;

    return ( fl+1 == n );
}
// -------------------------


template <typename Type>
bool is_weakly_concave(Type *f, ulong n)
// Return whether sequence is weakly concave
{
    if ( n<=2 )  return true;

    const ulong fl = last_weak_fall_idx(f, n);
    // if weakly concave ==> fl is a minimum
    const ulong rt = last_weak_rise_idx(f+fl, n-fl);
    const ulong rl = fl + rt;

    return ( rl+1 == n );
}
// -------------------------



#endif // !defined HAVE_CONVEX_H__
