/****************************************************************************
 * This file was derived from the CNCL library by the Pablo research group.
 *
 * The complete CNCL library is available at:
 *       http://www.comnets.rwth-aachen.de/doc/cncl.html
 *
 * The CNCL copyright notice is included here:
 *
 * |_|_|_  |_|_    |_    |_|_|_  |_               C O M M U N I C A T I O N
 *|_       |_  |_  |_  |_        |_                         N E T W O R K S
 *|_       |_  |_  |_  |_        |_                               C L A S S
 * |_|_|_  |_    |_|_    |_|_|_  |_|_|_|_                     L I B R A R Y
 *
 *
 *
 * Copyright (C) 1992-1998   Communication Networks
 *                           Aachen University of Technology
 *                           D-52056 Aachen
 *                           Germany
 *                           Email: cncl-adm@comnets.rwth-aachen.de
 *
 *
 * This library is free  software; you can  redistribute it and/or modify
 * it  under   the terms  of the GNU   Library  General Public License as
 * published by the  Free Software Foundation;  either  version 2 of  the
 * License, or  (at  your option)  any  later  version.  This  library is
 * distributed  in the  hope  that  it  will  be useful,  but WITHOUT ANY
 * WARRANTY;  without even the   implied  warranty of MERCHANTABILITY  or
 * FITNESS FOR A PARTICULAR PURPOSE.   See the GNU Library General Public
 * Library General Public License along with  this library; if not, write
 * to the Free Software Foundation,  675  Mass Ave, Cambridge, MA  02139,
 * USA.
 ****************************************************************************/

//   -*- C++ -*-
/*****************************************************************************
 *
 * Class: FlFSetArray --- Fuzzy set based on array with membership values
 *
 *****************************************************************************/

#include "FlFSetArray.h"

using std::endl;

/*
 * Constructors
 */
FlFSetArray::FlFSetArray()
    : FlFSet(), val((size_t)0), xmin(0), xmax(0)
{}
			     
FlFSetArray::FlFSetArray(size_t sz, double min, double max)
    : FlFSet(), val(sz), xmin(min), xmax(max)
{}

FlFSetArray::FlFSetArray(FlStringR xname, size_t sz, double min, double max)
    : FlFSet(xname), val(sz), xmin(min), xmax(max)
{}
			     
/*
 * Compute membership value
 */
double FlFSetArray::get_membership(double x) const
{
    if(x<xmin || x>xmax)
	return 0;
    
    int n = val.get_size();
    double dx = (xmax - xmin) / (n - 1);
    double x1, x2, y1, y2;
    int i = int( (x - xmin) / dx );

    if(i >= n)				// This happens, when x==xmax
	return val.get(i-1);
    if(i <  0)				// Shouldn't happen, but anyway ...
	return val.get(0);
    
    x1 = xmin + i*dx;
    x2 = x1   + dx;
    y1 = val.get(i);
    y2 = (i+1) >= n ? 0 : val.get(i+1);
    
    return y1 + (x - x1)*(y2 - y1)/(x2 - x1);
}



/*
 * Compute center of gravity for defuzzyfication
 */
double FlFSetArray::center_of_gravity(double /*min*/, double /*max*/) const
{
    /*
     * Compute center of gravity as
     *
     *   S_x = { \int_{min}^{max} x\cdot f(x)dx
     *     \over%------------------------------
     *           \int_{min}^{max} f(x)dx       }
     */

    int i, n;
    double x1, x2, y1, y2;
    double dx, dy;
    double sumn, sumd;
    
    sumn = sumd = 0;
    n    = val.get_size() - 1;
    dx   = (xmax - xmin) / n;

    for(i=0; i<n; i++)
    {
	x1 = xmin + i*dx;
	x2 = x1 + dx;
	y1 = val.get(i);
	y2 = val.get(i+1);
	dy = y2 - y1;

	double tmp;
	/*
	 * \int x*f(x) dx
	 */
	tmp = y1*(x2*x2 - x1*x1)/2 +
	    ( (x2*x2*x2 - x1*x1*x1)/3 - (x2*x2 - x1*x1)*x1/2 ) * dy/dx;
	sumn += tmp;
	/*
	 * \int f(x) dx
	 */
	sumd += dx * (y2 + y1)/2;
    }

    return sumn / sumd;
}



/*
 * Access to array of membership values
 */
double FlFSetArray::get(int i) const
{
    return val.get(i);
}


void FlFSetArray::put(int i, double x)
{
    val.put(i, x);
}


double & FlFSetArray::operator [] (int i)
{
    return val[i];
}



/*
 * Get size of array
 */
int FlFSetArray::get_n() const
{
    return val.get_size();
}


/*
 * 
 */
double FlFSetArray::highestPoint(double &x, double &y) const
{
    int n = val.get_size();
    double dx = (xmax - xmin) / (n - 1);
    int max = 0;

    for (int i = 0; i < n; i++)
      {
	if (val.get(i) > val.get(max))
	  max = i;
      }

    x = xmin + dx*max;
    y = val.get(max);
    return x;
}
			     
/***** Default I/O member function for FuzzyLib classes **************************/

// Normal output
void FlFSetArray::print(ostream &strm) const
{
    strm << "xmin=" << xmin << " xmax=" << xmax << " val=" << val << endl;
}

// Debug output
void FlFSetArray::dump(ostream &strm) const
{
    strm << "FlFSetArray { $Revision: 1.4 $  xmin="
	 << xmin << " xmax=" << xmax << endl
	 << "val=" << endl;
    val.dump(strm);
    strm << "}" << endl;
}
