/***********************************************************************
This file is part of KEEL-software, the Data Mining tool for regression,
classification, clustering, pattern mining and so on.
Copyright (C) 2004-2010
F. Herrera (herrera@decsai.ugr.es)
L. S�nchez (luciano@uniovi.es)
J. Alcal�-Fdez (jalcala@decsai.ugr.es)
S. Garc�a (sglopez@ujaen.es)
A. Fern�ndez (alberto.fernandez@ujaen.es)
J. Luengo (julianlm@decsai.ugr.es)
This program 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.
This program 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 this program. If not, see http://www.gnu.org/licenses/
**********************************************************************/
/**
* <p>
* @author Written by Jaume Bacardit (La Salle, Ram�n Llull University - Barcelona) 28/03/2004
* @author Modified by Xavi Sol� (La Salle, Ram�n Llull University - Barcelona) 23/12/2008
* @version 1.1
* @since JDK1.2
* </p>
*/
package keel.Algorithms.Genetic_Rule_Learning.GAssist;
import keel.Dataset.*;
import keel.Algorithms.Genetic_Rule_Learning.Globals.*;
public class ClassifierUBR
extends Classifier implements Cloneable {
/**
* <p>
* Classifier for the UBR intervalar knowledge representation
* </p>
*/
double[] crm;
int defaultClass;
public ClassifierUBR() {
isEvaluated = false;
}
public void initRandomClassifier() {
numRules = Parameters.initialNumberOfRules;
int ruleSize = Globals_UBR.ruleSize;
double probNominal = Parameters.probOne;
int nC = Parameters.numClasses;
crm = new double[numRules * ruleSize];
int base = 0;
if (Globals_DefaultC.defaultClassPolicy == Globals_DefaultC.AUTO) {
defaultClass = Rand.getInteger(0, Parameters.numClasses - 1);
}
else {
defaultClass = Globals_DefaultC.defaultClass;
}
for (int i = 0; i < numRules; i++) {
InstanceWrapper ins = null;
if (PopulationWrapper.smartInit) {
if (Globals_DefaultC.defaultClassPolicy != Globals_DefaultC.DISABLED) {
ins = PopulationWrapper.getInstanceInit(defaultClass);
}
else {
ins = PopulationWrapper.getInstanceInit(Parameters.numClasses);
}
}
for (int j = 0; j < Parameters.numAttributes; j++) {
if (Globals_UBR.types[j] == Attribute.NOMINAL) {
int value;
if (ins != null) {
value = ins.getNominalValue(j);
}
else {
value = -1;
}
for (int k = 0; k < Globals_UBR.size[j]; k++) {
if (k != value) {
if (Rand.getReal() < probNominal) {
crm[base + k] = 1;
}
else {
crm[base + k] = 0;
}
}
else {
crm[base + k] = 1;
}
}
}
else {
if (Rand.getReal() < 0.75) {
crm[base] = 1;
}
else {
crm[base] = 0;
}
if (Rand.getReal() < 0.75) {
crm[base + 1] = 1;
}
else {
crm[base + 1] = 0;
}
double min, max;
double size = (Rand.getReal() * 0.25 + 0.5)
* Globals_UBR.sizeD[j];
if (ins != null) {
double minD = Globals_UBR.minD[j];
double maxD = Globals_UBR.maxD[j];
double val = ins.getRealValue(j);
min = val - size / 2.0;
max = val + size / 2.0;
if (min < minD) {
min = minD;
}
if (max > maxD) {
max = maxD;
}
}
else {
min = Rand.getReal()
* (Globals_UBR.sizeD[j]
- size)
+ Globals_UBR.minD[j];
max = min + size;
}
if (Rand.getReal() < 0.5) {
crm[base + 2] = min;
crm[base + 3] = max;
}
else {
crm[base + 3] = min;
crm[base + 2] = max;
}
}
base += Globals_UBR.size[j];
}
if (ins != null) {
crm[base] = ins.classOfInstance();
}
else {
do {
crm[base] = Rand.getInteger(0, nC - 1);
}
while (Globals_DefaultC.enabled &&
crm[base] == defaultClass);
}
base++;
}
resetPerformance();
}
public double computeTheoryLength() {
int base = 0;
int ruleSize = Globals_UBR.ruleSize;
theoryLength = 0;
for (int i = 0; i < numRules; i++) {
if (PerformanceAgent.getActivationsOfRule(i) > 0) {
int base2 = base;
for (int j = 0; j < Parameters.numAttributes; j++) {
if (Globals_UBR.types[j] == Attribute.REAL) {
double min = crm[base2];
double max = crm[base2 + 1];
double vmin = crm[base2 + 2];
double vmax = crm[base2 + 3];
if (vmin > vmax) {
double tmp = vmin;
vmin = vmax;
vmax = tmp;
}
double dmin = Globals_UBR.minD[j];
double dmax = Globals_UBR.maxD[j];
if (min == 1) {
vmin = dmin;
}
if (max == 1) {
vmax = dmax;
}
theoryLength += 5.0;
if (dmax - dmin > 0) {
theoryLength += 5.0 - (vmax - vmin) / (dmax - dmin) * 5.0;
}
}
else {
double countFalses = 0;
int numValues = Globals_UBR.size[j];
for (int k = 0; k < numValues; k++) {
if (crm[base2 + k] == 0) {
countFalses++;
}
}
theoryLength += numValues
+ countFalses;
}
base2 += Globals_UBR.size[j];
}
}
if (Globals_DefaultC.enabled) {
theoryLength += 0.00000001;
}
base += ruleSize;
}
return theoryLength;
}
public int doMatch(InstanceWrapper ins) {
int nA = Parameters.numAttributes;
boolean okMatch;
int i, j;
int base = 0;
int ruleSize = Globals_UBR.ruleSize;
int[] valN = ins.getNominalValues();
double[] valR = ins.getRealValues();
for (i = 0; i < numRules; i++) {
okMatch = true;
int base2 = 0;
for (j = 0; okMatch && j < nA; j++) {
if (Globals_UBR.types[j] == Attribute.NOMINAL) {
if (crm[base + base2 + valN[j]] == 0) {
okMatch = false;
}
}
else {
double min = crm[base + base2 + 2];
double max = crm[base + base2 + 3];
if (max < min) {
double temp = max;
max = min;
min = temp;
}
if ( (crm[base + base2] == 0 && valR[j] < min) ||
(crm[base + base2 + 1] == 0 && valR[j] > max)) {
okMatch = false;
}
}
base2 += Globals_UBR.size[j];
}
if (okMatch) {
positionRuleMatch = i;
return (int) crm[base + base2];
}
base += Globals_UBR.ruleSize;
}
if (Globals_DefaultC.enabled) {
positionRuleMatch = numRules;
return defaultClass;
}
return -1;
}
public void printClassifier() {
int nA = Parameters.numAttributes;
int ruleSize = Globals_UBR.ruleSize;
String str;
int base = 0;
for (int i = 0; i < numRules; i++) {
str = i + ":";
for (int j = 0; j < nA; j++) {
if (Globals_UBR.types[j] == Attribute.NOMINAL) {
for (int k = 0; k < Globals_UBR.size[j]; k++) {
str += (int) crm[base + k];
}
}
else {
double minD = Globals_UBR.minD[j];
double maxD = Globals_UBR.maxD[j];
double min = crm[base + 2];
double max = crm[base + 3];
if (max < min) {
double temp = max;
max = min;
min = temp;
}
if (crm[base] == 1 || min <= minD) {
min = minD;
}
if (crm[base + 1] == 1 || max >= maxD) {
max = maxD;
}
str += "[" + min + "," + max + "]";
}
str += "|";
base += Globals_UBR.size[j];
}
str += (int) crm[base];
LogManager.println(str);
base++;
}
if (Globals_DefaultC.enabled) {
LogManager.println(numRules + ":Default rule -> " + defaultClass);
}
}
public int getNumRules() {
if (Globals_DefaultC.enabled) {
return numRules + 1;
}
return numRules;
}
public Classifier[] crossoverClassifiers(Classifier _parent2) {
ClassifierUBR offspring1 = new ClassifierUBR();
ClassifierUBR offspring2 = new ClassifierUBR();
ClassifierUBR parent2 = (ClassifierUBR) _parent2;
int ruleSize = Globals_UBR.ruleSize;
int ruleP1 = (int) Rand.getInteger(0, numRules - 1);
int ruleP2 = (int) Rand.getInteger(0, parent2.numRules - 1);
offspring1.numRules = ruleP1 + parent2.numRules - ruleP2;
offspring2.numRules = ruleP2 + numRules - ruleP1;
int cutPoint = (int) Rand.getInteger(0, Globals_UBR.ruleSize);
offspring1.defaultClass = offspring2.defaultClass = defaultClass;
offspring1.crm = new double[ruleSize * offspring1.numRules];
offspring2.crm = new double[ruleSize * offspring2.numRules];
System.arraycopy(crm, 0, offspring1.crm, 0, ruleP1 * ruleSize);
System.arraycopy(parent2.crm, 0, offspring2.crm, 0, ruleP2 * ruleSize);
int base1 = ruleP1 * ruleSize;
int base2 = ruleP2 * ruleSize;
System.arraycopy(crm, base1, offspring1.crm, base1, cutPoint);
System.arraycopy(parent2.crm, base2, offspring2.crm, base2, cutPoint);
System.arraycopy(crm, base1 + cutPoint, offspring2.crm, base2 + cutPoint,
ruleSize - cutPoint);
System.arraycopy(parent2.crm, base2 + cutPoint, offspring1.crm,
base1 + cutPoint, ruleSize - cutPoint);
base1 += ruleSize;
base2 += ruleSize;
System.arraycopy(crm, base1, offspring2.crm, base2,
(numRules - ruleP1 - 1) * ruleSize);
System.arraycopy(parent2.crm, base2, offspring1.crm, base1,
(parent2.numRules - ruleP2 - 1) * ruleSize);
Classifier[] ret = new Classifier[2];
ret[0] = offspring1;
ret[1] = offspring2;
return ret;
}
public Classifier copy() {
int ruleSize = Globals_UBR.ruleSize;
ClassifierUBR ret = new ClassifierUBR();
ret.numRules = numRules;
ret.theoryLength = theoryLength;
ret.exceptionsLength = ret.exceptionsLength;
ret.crm = new double[numRules * ruleSize];
System.arraycopy(crm, 0, ret.crm, 0, numRules * ruleSize);
ret.defaultClass = defaultClass;
ret.setAccuracy(accuracy);
ret.setFitness(fitness);
ret.isEvaluated = isEvaluated;
ret.setNumAliveRules(numAliveRules);
return ret;
}
private double mutationOffset(double value, double offMin, double offMax) {
double newVal;
if (Rand.getReal() < 0.5) {
newVal = value + Rand.getReal() * offMax;
}
else {
newVal = value - Rand.getReal() * offMin;
}
return newVal;
}
public void doMutation() {
int whichRule = (int) Rand.getInteger(0, numRules - 1);
int ruleSize = Globals_UBR.ruleSize;
int base = whichRule * ruleSize;
int pos;
if (Globals_DefaultC.numClasses > 1 && Rand.getReal() < 0.1) {
pos = ruleSize - 1;
double oldValue = crm[base + pos];
double newValue;
do {
newValue = Rand.getInteger(0, Parameters.numClasses - 1);
}
while (newValue == oldValue ||
(Globals_DefaultC.enabled && (int) newValue == defaultClass));
crm[base + pos] = newValue;
}
else {
int attr = (int) Rand.getInteger(0, Parameters.numAttributes - 1);
if (Globals_UBR.types[attr] == Attribute.NOMINAL) {
int val = (int) Rand.getInteger(0, Globals_UBR.size[attr] - 1);
pos = base + Globals_UBR.offset[attr] + val;
if (crm[pos] == 1) {
crm[pos] = 0;
}
else {
crm[pos] = 1;
}
}
else {
int val = (int) Rand.getInteger(0, 3);
pos = base + Globals_UBR.offset[attr] + val;
if (val < 2) {
if (crm[pos] == 1) {
crm[pos] = 0;
}
else {
crm[pos] = 1;
}
}
else {
double minOff, maxOff;
minOff = maxOff = 0.7 * Globals_UBR.sizeD[attr];
if (crm[pos] - minOff < Globals_UBR.minD[attr]) {
minOff = crm[pos] - Globals_UBR.minD[attr];
}
if (crm[pos] + maxOff > Globals_UBR.maxD[attr]) {
maxOff = Globals_UBR.maxD[attr] - crm[pos];
}
crm[pos] = mutationOffset(crm[pos], minOff, maxOff);
}
}
}
isEvaluated = false;
}
public void deleteRules(int[] whichRules) {
if (numRules == 1 || whichRules.length == 0) {
return;
}
int ruleSize = Globals_UBR.ruleSize;
int rulesToDelete = whichRules.length;
if (whichRules[rulesToDelete - 1] == numRules) {
rulesToDelete--;
}
double[] newCrm = new double[ruleSize * (numRules - rulesToDelete)];
int countPruned = 0;
int baseOrig = 0;
int baseNew = 0;
for (int i = 0; i < numRules; i++) {
if (countPruned < rulesToDelete) {
if (i != whichRules[countPruned]) {
System.arraycopy(crm, baseOrig, newCrm, baseNew, ruleSize);
baseNew += ruleSize;
}
else {
countPruned++;
}
}
else {
System.arraycopy(crm, baseOrig, newCrm, baseNew, ruleSize);
baseNew += ruleSize;
}
baseOrig += ruleSize;
}
numRules -= rulesToDelete;
crm = newCrm;
}
public double getLength() {
return numAliveRules;
}
public int numSpecialStages() {
return 0;
}
public void doSpecialStage(int stage) {}
public int getNiche() {
if (Globals_DefaultC.defaultClassPolicy != Globals_DefaultC.AUTO) {
return 0;
}
return defaultClass;
}
public int getNumNiches() {
if (Globals_DefaultC.defaultClassPolicy != Globals_DefaultC.AUTO) {
return 1;
}
return Parameters.numClasses;
}
}