//--------------------------------------------------------------------------------// // 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.xfedit; import xfuzzy.lang.*; import xfuzzy.util.*; import javax.swing.*; import javax.swing.event.*; import javax.swing.table.*; import java.awt.*; /** * Modelo de la tabla para la representaci�n de una base de reglas * en formato tabular * * @author Francisco Jos� Moreno Velo * */ public class XfeditRulebaseTableModel extends AbstractTableModel implements TableCellRenderer { /** * C�digo asociado a la clase serializable */ private static final long serialVersionUID = 95505666603037L; //----------------------------------------------------------------------------// // MIEMBROS PRIVADOS // //----------------------------------------------------------------------------// /** * Etiqueta para representar las celdas no editables */ private XLabel label; /** * Etiqueta para representar las celdas editables */ private JLabel text; /** * Lista de variables de entrada de la base de reglas */ private Variable[] input; /** * Lista de variables de salida de la base de reglas */ private Variable[] output; /** * Grados de activaci�n de cada regla */ private double[] degree; /** * Matriz de las funciones de pertenencia de los antecedentes de * cada regla */ private LinguisticLabel[][] ipmf; /** * Matriz de las funciones de pertenencia de los consecuentes de * cada regla */ private LinguisticLabel[][] opmf; /** * Editor de las celdas de las variables de entrada */ private DefaultCellEditor[] ieditor; /** * Editor de las celdas de las variables de salida */ private DefaultCellEditor[] oeditor; /** * Marcador para indicar si la base de reglas se puede * representar en formato tabular */ private boolean valid; //----------------------------------------------------------------------------// // CONSTRUCTOR // //----------------------------------------------------------------------------// /** * Constructor */ public XfeditRulebaseTableModel(Rulebase copy) { super(); initialize(copy); } //----------------------------------------------------------------------------// // M�TODOS P�BLICOS // //----------------------------------------------------------------------------// /** * Obtiene la referencia a la variable de entrada i-�sima */ public Variable getInput(int i) { return this.input[i]; } /** * Obtiene la referencia a la variable de salida i-�sima */ public Variable getOutput(int i) { return this.output[i]; } /** * Obtiene el n�mero de variables de entrada del modelo */ public int getInputLength() { return this.input.length; } /** * Obtiene el n�mero de variables de salida del modelo */ public int getOutputLength() { return this.output.length; } /** * Verifica que la base de reglas cumpla las restricciones de la forma tabular */ public boolean isValid() { return valid; } /** * Obtiene el n�mero de columnas de la tabla */ public int getColumnCount() { return (input.length*2+3+output.length); } /** * Obtiene el n�mero de filas de la tabla */ public int getRowCount() { return degree.length+1; } /** * Obtiene un elemento de la tabla */ public Object getValueAt(int row, int column) { if(column == 0 && row == degree.length) return "*"; if(row == degree.length) return ""; if(column == 0) return ""+row; if(column == 1) return ""+degree[row]; if(column == 2) return "if"; if(column == (input.length*2+2) ) return "->"; if(isInputIndex(column)) return ipmf[row][getInputIndex(column)]; if(isOutputIndex(column)) return opmf[row][getOutputIndex(column)]; return "&"; } /** * Asigna un elemento de la tabla */ public void setValueAt(Object value, int row, int column) { if(row == degree.length) addRow(); if(column == 1) { double deg; try { deg = Double.parseDouble((String) value); } catch(Exception ex) { deg = -1; } if(deg <0.0 || deg > 1.0) Toolkit.getDefaultToolkit().beep(); else degree[row] = deg; } if(isInputIndex(column)) { LinguisticLabel pmf; try { pmf = (LinguisticLabel) value; } catch (Exception ex) { pmf = null; } ipmf[row][getInputIndex(column)] = pmf; } if(isOutputIndex(column)) { LinguisticLabel pmf; try { pmf = (LinguisticLabel) value; } catch (Exception ex) { pmf = null; } opmf[row][getOutputIndex(column)] = pmf; } fireTableCellUpdated(row, column); } /** * Obtiene las reglas representadas en la tabla */ public boolean getRules(Rulebase copy) { copy.removeAllRules(); for(int i=0; i<ipmf.length; i++) { boolean flag = false; for(int j=0; j<ipmf[i].length; j++) if(ipmf[i][j] != null) flag = true; if(!flag) return false; } for(int i=0; i<opmf.length; i++) { boolean flag = false; for(int j=0; j<opmf[i].length; j++) if(opmf[i][j] != null) flag = true; if(!flag) return false; } for(int i=0; i<degree.length; i++) { Relation premise = null; for(int j=input.length-1; j>=0; j--) if(ipmf[i][j] != null) { Relation rel = Relation.create(Relation.IS,null,null,input[j], ipmf[i][j],null); if(premise == null) premise = rel; else premise=Relation.create(Relation.AND,rel,premise,null,null,copy); } Rule newrule = new Rule(premise,degree[i]); for(int j=0; j<opmf[i].length; j++) if(opmf[i][j] != null) newrule.add(new Conclusion(output[j],opmf[i][j],copy)); copy.addRule(newrule); } return true; } /** * Obtiene el t�tulo de una columna de la tabla */ public String getColumnName(int column) { if(column == 0) return "Rule"; if(column == 1 || column == 2) return ""; if(isInputIndex(column)) return input[getInputIndex(column)].getName(); if(isOutputIndex(column)) return output[getOutputIndex(column)].getName(); return ""; } /** * Obtiene el editor de las celdas de la tabla */ public TableCellEditor getEditor(int row, int column) { if(isInputIndex(column)) return ieditor[getInputIndex(column)]; if(isOutputIndex(column)) return oeditor[getOutputIndex(column)]; return null; } /** * Obtiene la clase de un elemento de la tabla */ public Class getColumnClass(int column) { if(column == 1) return Object.class; if(isInputIndex(column) || isOutputIndex(column)) return JComboBox.class; return XLabel.class; } /** * Verifica que una celda sea editable */ public boolean isCellEditable(int rowIndex, int columnIndex) { if(columnIndex == 1) return true; if(isInputIndex(columnIndex) || isOutputIndex(columnIndex)) return true; return false; } /** * Obtiene el componente que representa cada celda */ public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { if(column != 1 && !isInputIndex(column) && !isOutputIndex(column) ) { label.setText(value.toString()); return label; } if(isSelected) { text.setForeground(table.getSelectionForeground()); text.setBackground(XConstants.textselectedbg); } else { text.setForeground(Color.black); text.setBackground(XConstants.textbackground); } if(row == degree.length) { text.setText(""); return text; } if(column == 1) { text.setText(value.toString()); return text; } if(isInputIndex(column)) { int index = getInputIndex(column); if(ipmf[row][index] == null) text.setText(""); else text.setText(input[index]+" == "+ipmf[row][index]); } if(isOutputIndex(column)) { int index = getOutputIndex(column); if(opmf[row][index] == null) text.setText(""); else text.setText(output[index]+" = "+opmf[row][index]); } return text; } /** * A�ade una fila (regla) a la tabla */ public void addRow() { LinguisticLabel auxipmf[][] = new LinguisticLabel[degree.length+1][input.length]; System.arraycopy(ipmf,0,auxipmf,0,degree.length); auxipmf[degree.length] = new LinguisticLabel[input.length]; ipmf = auxipmf; LinguisticLabel auxopmf[][] = new LinguisticLabel[degree.length+1][output.length]; System.arraycopy(opmf,0,auxopmf,0,degree.length); auxopmf[degree.length] = new LinguisticLabel[output.length]; opmf = auxopmf; double auxdeg[] = new double[degree.length + 1]; System.arraycopy(degree,0,auxdeg,0,degree.length); auxdeg[degree.length] = 1.0; degree = auxdeg; fireTableChanged(new TableModelEvent(this, degree.length, degree.length, TableModelEvent.ALL_COLUMNS, TableModelEvent.INSERT)); } /** * Elimina una fila (regla) de la tabla */ public void removeRow(int row) { LinguisticLabel auxipmf[][] = new LinguisticLabel[degree.length-1][input.length]; System.arraycopy(ipmf,0,auxipmf,0,row); System.arraycopy(ipmf,row+1,auxipmf,row,degree.length-row-1); ipmf = auxipmf; LinguisticLabel auxopmf[][] = new LinguisticLabel[degree.length-1][output.length]; System.arraycopy(opmf,0,auxopmf,0,row); System.arraycopy(opmf,row+1,auxopmf,row,degree.length-row-1); opmf = auxopmf; double auxdeg[] = new double[degree.length - 1]; System.arraycopy(degree,0,auxdeg,0,row); System.arraycopy(degree,row+1,auxdeg,row,degree.length-row-1); degree = auxdeg; fireTableChanged(new TableModelEvent(this, row, row, TableModelEvent.ALL_COLUMNS, TableModelEvent.DELETE)); } //----------------------------------------------------------------------------// // M�TODOS PRIVADOS // //----------------------------------------------------------------------------// /** * Inicializa el contenido de la tabla */ private void initialize(Rulebase copy) { label = new XLabel(""); label.setLabelFont(XConstants.textfont); text = new JLabel(""); text.setFont(XConstants.textfont); text.setOpaque(true); input = copy.getInputs(); output = copy.getOutputs(); initializeInputCombo(); initializeOutputCombo(); valid = initializeRules(copy); } /** * Crea los men�s desplegables de las variables de entrada */ private void initializeInputCombo() { ieditor = new DefaultCellEditor[input.length]; for(int i=0; i<input.length; i++) { JComboBox newcombo = new JComboBox(); newcombo.setBackground(XConstants.textbackground); newcombo.setFont(XConstants.textfont); newcombo.setEditable(false); newcombo.setRenderer(new XfeditRulebaseTableRenderer(this,i,true)); newcombo.addItem(""); LinguisticLabel[] pmf = input[i].getType().getAllMembershipFunctions(); for(int k=0; k<pmf.length; k++) newcombo.addItem(pmf[k]); ieditor[i] = new DefaultCellEditor(newcombo); } } /** * Crea los men�s desplegables de las variables de salida */ private void initializeOutputCombo() { oeditor = new DefaultCellEditor[output.length]; for(int i=0; i<output.length; i++) { JComboBox newcombo = new JComboBox(); newcombo.setBackground(XConstants.textbackground); newcombo.setFont(XConstants.textfont); newcombo.setEditable(false); newcombo.setRenderer(new XfeditRulebaseTableRenderer(this,i,false)); newcombo.addItem(""); LinguisticLabel[] pmf = output[i].getType().getAllMembershipFunctions(); for(int k=0; k<pmf.length; k++) newcombo.addItem(pmf[k]); oeditor[i] = new DefaultCellEditor(newcombo); } } /** * Genera el contenido de las celdas (proposiciones) */ private boolean initializeRules(Rulebase copy) { Rule[] rule = copy.getRules(); degree = new double[rule.length]; ipmf = new LinguisticLabel[rule.length][input.length]; opmf = new LinguisticLabel[rule.length][output.length]; for(int i=0; i<rule.length; i++) { Relation rel[] = crumblePremise(rule[i]); Conclusion conc[] = crumbleConclusion(rule[i]); if(rel == null || conc == null) return false; degree[i] = rule[i].getDegree(); for(int j=0; j<input.length; j++) if(rel[j] != null) ipmf[i][j] = rel[j].getMembershipFunction(); for(int j=0; j<output.length; j++) if(conc[j] != null) opmf[i][j] = conc[j].getMembershipFunction(); } return true; } /** * Disgrega el antecedente de una regla formado por conjunci�n de * proposiciones de igualdad */ private Relation[] crumblePremise(Rule rl) { Relation crumble[] = new Relation[input.length]; Relation disorder[] = crumbleRelation(rl.getPremise()); if(disorder == null) return null; for(int i=0; i<disorder.length; i++) { int index = -1; Variable var = disorder[i].getVariable(); for(int j=0; j<input.length; j++) if(input[j] == var) index = j; if(crumble[index] != null) return null; crumble[index] = disorder[i]; } return crumble; } /** * Disgrega el conjunto de conclusiones de una regla */ private Conclusion[] crumbleConclusion(Rule rl) { Conclusion disorder[] = rl.getConclusions(); Conclusion crumble[] = new Conclusion[output.length]; for(int i=0; i<disorder.length; i++) { int index = -1; Variable var = disorder[i].getVariable(); for(int j=0; j<output.length; j++) if(output[j] == var) index = j; if(crumble[index] != null) return null; crumble[index] = disorder[i]; } return crumble; } /** * Disgrega una proposici�n compuesta */ private Relation[] crumbleRelation(Relation rel) { switch(rel.getKind()) { case Relation.IS: Relation[] out = new Relation[1]; out[0] = rel; return out; case Relation.AND: Relation[] left = crumbleRelation(rel.getLeftRelation()); Relation[] right = crumbleRelation(rel.getRightRelation()); if(left == null || right == null) return null; Relation[] crumble = new Relation[left.length + right.length]; for(int i=0; i<left.length; i++) crumble[i] = left[i]; for(int i=0; i<right.length; i++) crumble[left.length + i] = right[i]; return crumble; default: return null; } } /** * Estudia si el �ndice corresponde a una columna de entrada */ private boolean isInputIndex(int column) { if(column>2 && column<input.length*2+2 && (column-3)%2==0) return true; return false; } /** * Estudia si el �ndice corresponde a una columna de salida */ private boolean isOutputIndex(int column) { if(column>input.length*2+2 && column<input.length*2+3+output.length) return true; return false; } /** * Obtiene el indice de la variable de entrada de una columna */ private int getInputIndex(int column) { if(column>2 && column<input.length*2+2 && (column-3)%2==0) return (column-3)/2; return -1; } /** * Obtiene el �ndice de la variable de salida de una columna */ private int getOutputIndex(int column) { if(column > input.length*2+2 && column < input.length*2+3+output.length) return column-input.length*2-3; return -1; } }