/**
* Global Sensor Networks (GSN) Source Code
* Copyright (c) 2006-2016, Ecole Polytechnique Federale de Lausanne (EPFL)
*
* This file is part of GSN.
*
* GSN is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GSN 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GSN. If not, see <http://www.gnu.org/licenses/>.
*
* File: src/ch/epfl/gsn/utils/models/ChebyshevPolynomialModel.java
*
* @author Alexandru Arion
* @author Sofiane Sarni
*
*/
package ch.epfl.gsn.utils.models;
import java.util.Collections;
import java.util.List;
import ch.epfl.gsn.utils.models.auxiliar.ChebyshevPolynomial;
import de.jtem.numericalMethods.calculus.functionApproximation.ChebyshevApproximation;
import de.jtem.numericalMethods.calculus.functionApproximation.RealFunction;
public class ChebyshevPolynomialModel implements IModel, RealFunction{
int degree;
int windowSize;
double errorBound;
long[] timestamps;
double[] stream;
double c, d; //input boundaries
double[] coefs;
int currentPos;
public ChebyshevPolynomialModel(int degree, int windowSize, double errorBound, long[] timestamps, double[] stream)
{
this.degree = degree;
this.windowSize = windowSize;
this.timestamps = timestamps;
this.stream = stream;
this.errorBound = errorBound;
this.coefs = new double[degree + 1];
}
public boolean FitAndMarkDirty(double[] processed, double[] dirtyness, double[] quality) {
//fit piecewise
this.currentPos = 0;
do
{
this.c = this.timestamps[currentPos];
if(currentPos + this.windowSize - 1 < this.timestamps.length)
this.d = this.timestamps[currentPos + this.windowSize - 1];
else
this.d = this.timestamps[this.timestamps.length - 1];
ChebyshevApproximation.fit(this.coefs, this);
//build processed
for(int i = currentPos; i <= this.currentPos + this.windowSize - 1 && i < this.timestamps.length; i++)
{
processed[i] = ComputeValue(this.timestamps[i]);
if(Math.abs(processed[i] - stream[i]) <= this.errorBound)
{
dirtyness[i] = 0;
}
else
dirtyness[i] = 1;
}
this.currentPos += this.windowSize;
}
while(currentPos < this.timestamps.length - 1 - this.degree);
for(int i = currentPos; i < this.timestamps.length; i++)
{
processed[i] = stream[i];
dirtyness[i] = 0;
}
return true;
}
double ComputeValue(double input) {
double retval = 0.0;
//transform the input in [-1, 1]
//it may fall outside, it will always fall outside, so we must compute manually
double new_input = 2/(d - c) * input + (c + d)/(c - d);
ChebyshevPolynomial cp = new ChebyshevPolynomial(this.degree, this.coefs);
retval = cp.Calculate(new_input);
//retval = ChebyshevApproximation.evaluate(this.coefs, new_input);
return retval;
}
public double valueAt(double x) {
double retval = 0.0;
//transform the input in [c, d]
double new_x = (d-c)/2 * x + (c+d)/2;
//locate the new_x in the window
double min = Double.MAX_VALUE;
int i = this.currentPos;
int poz = i;
for(; i < this.currentPos + this.windowSize && i < this.timestamps.length; i++)
{
if(Math.abs(new_x - this.timestamps[i]) < min)
{
min = Math.abs(new_x - this.timestamps[i]);
poz = i;
}
}
//new_x is between i - 1 and i
retval = this.stream[poz];
return retval;
}
}