//--------------------------------------------------------------------------------//
// COPYRIGHT NOTICE //
//--------------------------------------------------------------------------------//
// Copyright (c) 2012, Instituto de Microelectronica de Sevilla (IMSE-CNM) //
// //
// All rights reserved. //
// //
// Redistribution and use in source and binary forms, with or without //
// modification, are permitted provided that the following conditions are met: //
// //
// * Redistributions of source code must retain the above copyright notice, //
// this list of conditions and the following disclaimer. //
// //
// * Redistributions in binary form must reproduce the above copyright //
// notice, this list of conditions and the following disclaimer in the //
// documentation and/or other materials provided with the distribution. //
// //
// * Neither the name of the IMSE-CNM nor the names of its contributors may //
// be used to endorse or promote products derived from this software //
// without specific prior written permission. //
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" //
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE //
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE //
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE //
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL //
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR //
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER //
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, //
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE //
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. //
//--------------------------------------------------------------------------------//
package xfuzzy.lang;
/**
* Clase abstracta que describe el comportamiento com�n de todas
* las funciones param�tricas definidas en los paquetes
*
* @author Francisco Jos� Moreno Velo
*
*/
public abstract class ParametricFunction {
//----------------------------------------------------------------------------//
// MIEMBROS PRIVADOS //
//----------------------------------------------------------------------------//
/**
* Indicador para sabe si alg�n par�metro de la funci�n debe ser
* ajustado en un proceso de aprendizaje autom�tico
*/
private boolean adjustable = true;
/**
* Nombre de la funci�n
*/
private String function;
/**
* Nombre del paquete al que pertenece la funci�n
*/
private String pkg;
/**
* Nombre de la lista de par�metros
*/
private String paramlistname;
/**
* Lista de par�metros definidos individualmente
*/
protected Parameter singleparam[];
/**
* Lista de par�metros definidos bajo una lista
*/
protected Parameter paramlist[];
//----------------------------------------------------------------------------//
// CONSTRUCTOR //
//----------------------------------------------------------------------------//
/**
* Constructor
*/
public ParametricFunction(String pkg, String function) {
this.pkg = pkg;
this.function = function;
}
//----------------------------------------------------------------------------//
// M�TODOS P�BLICOS //
//----------------------------------------------------------------------------//
//----------------------------------------------------------------------------//
// M�todos comunes de los objetos XFL3 //
//----------------------------------------------------------------------------//
/**
* Genera la descripci�n XFL3 de la funci�n param�trica
*/
public String getXflDescription() {
String code = pkg+"."+function+"(";
double p[] = get();
for(int i=0; i<p.length; i++) code += (i>0? "," : "")+p[i];
code += ");";
return code;
}
//----------------------------------------------------------------------------//
// M�todos de acceso a los campos //
//----------------------------------------------------------------------------//
/**
* Obtiene el nombre del paquete de funciones
*/
public String getPackageName() {
return this.pkg;
}
/**
* Obtiene el nombre de la funci�n
*/
public String getFunctionName() {
return this.function;
}
//----------------------------------------------------------------------------//
// M�todos de acceso a la condici�n de ajustabilidad //
//----------------------------------------------------------------------------//
/**
* Analiza si alg�n par�metro de la funci�n es ajustable
*/
public void setAdjustable() {
this.adjustable = false;
for(int i=0; i<singleparam.length; i++)
if(singleparam[i].isAdjustable()) this.adjustable = true;
if(paramlist != null) {
for(int i=0; i<paramlist.length; i++)
if(paramlist[i].isAdjustable()) this.adjustable = true;
}
}
/**
* Verifica si alg�n par�metro de la funci�n es ajustable
*/
public boolean isAdjustable() {
return this.adjustable;
}
/**
* Obtiene cuales de los par�metros son ajustables
*/
public boolean[] getAdjustable() {
int singlelength = singleparam.length;
int listlength = (paramlist == null? 0 : paramlist.length);
boolean[] d = new boolean[singlelength+listlength];
for(int i=0; i<singlelength; i++) d[i] = singleparam[i].isAdjustable();
for(int i=0; i<listlength; i++) d[singlelength+i]=paramlist[i].isAdjustable();
return d;
}
//----------------------------------------------------------------------------//
// M�todos de manejo de los par�metros //
//----------------------------------------------------------------------------//
/**
* Obtiene el nombre de la lista de par�metros
*/
public String getParamListName() {
return this.paramlistname;
}
/**
* Asigna el nombre de la lista de par�metros
*/
public void setParamListName(String name) {
this.paramlistname = name;
}
/**
* Verifica si la funci�n define una lista de par�metros
*/
public boolean hasParamList() {
return (this.paramlistname != null && this.paramlistname.length() > 0);
}
/**
* Obtiene las referencias a los par�metros simples
*/
public Parameter[] getSingleParameters() {
return this.singleparam;
}
/**
* Asigna las referencias a los parametros simples
*/
public void setSingleParameters(Parameter[] param) {
this.singleparam = param;
}
/**
* Obtiene las referencias de la lista de par�metros
*/
public Parameter[] getParamList() {
return this.paramlist;
}
/**
* Asigna las referencias a la lista de par�metros
*/
public void setParamList(Parameter[] list) {
this.paramlist = list;
}
/**
* Obtiene las referencias a todos los par�metros
*/
public Parameter[] getParameters() {
int listlength = (paramlist == null? 0 : paramlist.length);
Parameter param[] = new Parameter[singleparam.length+listlength];
for(int i=0;i<singleparam.length; i++) param[i] = singleparam[i];
for(int i=0;i<listlength; i++) param[i+singleparam.length]=paramlist[i];
return param;
}
//-------------------------------------------------------------//
// //
//-------------------------------------------------------------//
/**
* Obtiene el n�mero de par�metros
*/
public int getNumberOfParameters() {
int listlength = (paramlist == null? 0 : paramlist.length);
return singleparam.length+listlength;
}
/**
* Asigna los valores de los par�metros de la funci�n
*/
public void set(double p[]) throws XflException {
if(p.length<singleparam.length) throw new XflException(34);
if(p.length>singleparam.length && !hasParamList()) throw new XflException(34);
for(int i=0; i<singleparam.length; i++) singleparam[i].value = p[i];
paramlist = new Parameter[p.length-singleparam.length];
for(int i=0; i<paramlist.length; i++) {
paramlist[i] = new Parameter(paramlistname);
paramlist[i].value = p[singleparam.length+i];
}
}
/**
* Asigna el valor del primer par�metro de la funci�n
*/
public void set(double p) {
singleparam[0].value = p;
}
/**
* Obtiene los valores de los par�metros de la funci�n
*/
public double[] get() {
int listlength = (paramlist == null? 0 : paramlist.length);
double[] p = new double[singleparam.length+listlength];
for(int i=0; i<singleparam.length; i++) p[i] = singleparam[i].value;
for(int i=0; i<listlength; i++) p[singleparam.length+i] = paramlist[i].value;
return p;
}
/**
* Obtiene los valores de la lista de par�metros de la funci�n
*/
public double[] getParamListValues() {
int listlength = (paramlist == null? 0 : paramlist.length);
double[] p = new double[listlength];
for(int i=0; i<listlength; i++) p[i] = paramlist[i].value;
return p;
}
/**
* Obtiene los desplazamientos de los par�metros de la funci�n
*/
public double[] getDesp() {
int singlelength = singleparam.length;
int listlength = (paramlist == null? 0 : paramlist.length);
double[] d = new double[singlelength+listlength];
for(int i=0; i<singlelength; i++) d[i] = singleparam[i].getDesp();
for(int i=0; i<listlength; i++) d[singlelength+i] = paramlist[i].getDesp();
return d;
}
/**
* A�ade un valor a la derivada de un parametro
*/
public void addDeriv(int index, double deriv) {
if(index < singleparam.length) this.singleparam[index].addDeriv(deriv);
else this.paramlist[index-singleparam.length].addDeriv(deriv);
}
/**
* M�todo por defecto para actualizar los par�metros
*/
public void update() {
if(!adjustable) return;
Parameter parameter[] = getParameters();
double[] desp = getDesp();
double[] prevvalue = get();
for(int i=0; i<parameter.length; i++) parameter[i].value += desp[i];
if(!test()) {
for(int i=0; i<parameter.length; i++) parameter[i].value -= desp[i];
for(int j=0; j<10; j++) {
for(int i=0; i<desp.length; i++) desp[i] /= 2;
for(int i=0; i<parameter.length; i++) parameter[i].value += desp[i];
if(!test())
for(int i=0; i<parameter.length; i++) parameter[i].value -= desp[i];
}
}
for(int i=0; i<parameter.length; i++) {
parameter[i].setDesp(0.0);
parameter[i].setPrevDesp(parameter[i].value - prevvalue[i]);
}
}
//----------------------------------------------------------------------------//
// M�TODOS P�BLICOS ABSTRACTOS //
//----------------------------------------------------------------------------//
/**
* Verifica que los valores de los par�metros sean correctos
*/
public abstract boolean test();
//----------------------------------------------------------------------------//
// M�TODOS PRIVADOS //
//----------------------------------------------------------------------------//
/**
* Actualiza los valores y desplazamientos previos
*/
protected void updateValues(double[] pos) {
for(int i=0; i<singleparam.length; i++) {
double prev = singleparam[i].value;
singleparam[i].value = pos[i];
singleparam[i].setDesp(0.0);
singleparam[i].setPrevDesp(pos[i] - prev);
}
if(paramlist!= null) for(int i=0; i<paramlist.length; i++) {
int j = i+singleparam.length;
double prev = paramlist[i].value;
paramlist[i].value = pos[j];
paramlist[i].setDesp(0.0);
paramlist[i].setPrevDesp(pos[j] - prev);
}
}
/**
* Verifica que una lista de valores est� ordenada
*/
protected boolean sorted(double[] p) {
for(int i=1; i<p.length; i++) if(p[i] <= p[i-1]) return false;
return true;
}
/**
* M�todo que desplaza un conjunto de valores manteniendo su orden
*/
protected double[] sortedUpdate(double[] value, double[] desp, double step,
boolean[] enable){
int[] cont = new int[value.length];
double[] time = new double[value.length-1];
double[] pos = new double[value.length];
double oldval = value[0]-3*step;
for(int i=0; i<value.length; i++) {
pos[i] = (value[i] < oldval+step? oldval+step : value[i]);
cont[i] = 1;
oldval = pos[i];
}
double timeup = 1;
int num = value.length;
while(timeup>0) {
double mintime= timeup;
for(int i=0;i<num-1;i++) {
double dist = (pos[i+1]-pos[i] -step*(cont[i]+cont[i+1])/2 );
if(desp[i]==desp[i+1]) time[i]=2;
else if(dist<0 && desp[i]>desp[i+1]) time[i]=0; /* por redondeos */
else time[i]= dist/(desp[i]-desp[i+1]);
if(time[i]>=0 && time[i]<mintime) mintime = time[i];
}
for(int i=0;i<num;i++) pos[i]+=desp[i]*mintime;
for(int i=0;i<num-1;i++)
if(time[i]==mintime) {
if(enable[i] && enable[i+1]) {
desp[i]=(cont[i]*desp[i]+cont[i+1]*desp[i+1])/(cont[i]+cont[i+1]);
pos[i]=(cont[i]*pos[i]+cont[i+1]*pos[i+1])/(cont[i]+cont[i+1]);
cont[i] += cont[i+1];
num--;
for(int j=i+1;j<num;j++) {
desp[j]= desp[j+1];
pos[j]= pos[j+1];
cont[j]= cont[j+1];
enable[j]= enable[j+1];
}
} else if(!enable[i] && enable[i+1]) {
desp[i+1]= 0;
pos[i+1]= pos[i]+step;
} else if(enable[i] && !enable[i+1]) {
desp[i]= 0;
pos[i]= pos[i+1]-step;
}
}
timeup -= mintime;
}
double [] output = new double[value.length];
int i=0, j=1-cont[i];
for(int k=0; k<value.length; k++) {
output[k] = pos[i] + j*step/2;
j = j+2;
cont[i]--;
if(cont[i]==0 && k<value.length-1) { i++; j=1-cont[i]; }
}
return output;
}
}