com.tesora.dve.tools.aitemplatebuilder.FuzzyLinguisticVariable.java Source code

Java tutorial

Introduction

Here is the source code for com.tesora.dve.tools.aitemplatebuilder.FuzzyLinguisticVariable.java

Source

package com.tesora.dve.tools.aitemplatebuilder;

/*
 * #%L
 * Tesora Inc.
 * Database Virtualization Engine
 * %%
 * Copyright (C) 2011 - 2014 Tesora Inc.
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License, version 3,
 * as published by the Free Software Foundation.
 * 
 * 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 Affero General Public License for more details.
 * 
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 * #L%
 */

import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

import net.sourceforge.jFuzzyLogic.FIS;
import net.sourceforge.jFuzzyLogic.FunctionBlock;
import net.sourceforge.jFuzzyLogic.rule.Rule;
import net.sourceforge.jFuzzyLogic.rule.Variable;

import org.apache.commons.lang.math.DoubleRange;
import org.apache.log4j.Logger;

import com.tesora.dve.common.MathUtils;
import com.tesora.dve.common.PEFileUtils;
import com.tesora.dve.exceptions.PECodingException;
import com.tesora.dve.exceptions.PEException;

public abstract class FuzzyLinguisticVariable implements TemplateItem {

    private static final Logger logger = Logger.getLogger(FuzzyLinguisticVariable.class);

    private static final Comparator<FuzzyLinguisticVariable> MODEL_SCORE_COMPARATOR = new Comparator<FuzzyLinguisticVariable>() {
        @Override
        public int compare(FuzzyLinguisticVariable a, FuzzyLinguisticVariable b) {
            if ((a == null) || (b == null)) {
                throw new NullPointerException();
            }

            if (a.getScore() > b.getScore()) {
                return 1;
            } else if (a.getScore() < b.getScore()) {
                return -1;
            } else {
                return 0;
            }
        }
    };

    protected interface FlvName {
        public String get();
    }

    private enum Variables implements FlvName {
        SCORE_FLV_NAME {
            @Override
            public String get() {
                return "desirability";
            }
        };
    }

    private static final String RULE_NAME_PREFIX_SEPARATOR = "_";
    private static final String FCL_SCHEMA_FILE_NAME = "DistributionModels.fcl";
    private static final DoubleRange VALID_RULE_WEIGHT_RANGE = new DoubleRange(0, 1);
    private static final double DEFAULT_RULE_WEIGHT = 1.0;

    private final FunctionBlock ai;

    public static double toPercent(final double value, final double total) {
        return 100.0 * (value / total);
    }

    public static Comparator<FuzzyLinguisticVariable> getScoreComparator() {
        return MODEL_SCORE_COMPARATOR;
    }

    public static List<FuzzyTableDistributionModel> evaluateDistributionModels(
            final FuzzyTableDistributionModel... distributionModels) {
        return evaluateDistributionModels(Collections.EMPTY_MAP, distributionModels);
    }

    public static List<FuzzyTableDistributionModel> evaluateDistributionModels(
            final Map<FlvName, Double> ruleWeights, final FuzzyTableDistributionModel... distributionModels) {
        final List<FuzzyTableDistributionModel> sortedDistributionModels = Arrays.asList(distributionModels);
        for (final FuzzyLinguisticVariable distributionModel : sortedDistributionModels) {
            distributionModel.setRuleWeights(ruleWeights);
            distributionModel.evaluate();
        }

        Collections.sort(sortedDistributionModels, getScoreComparator());

        return sortedDistributionModels;
    }

    protected FuzzyLinguisticVariable(final String fclBlockName) throws PECodingException {
        try (final InputStream fclSchema = PEFileUtils.getResourceStream(FuzzyLinguisticVariable.class,
                FCL_SCHEMA_FILE_NAME)) {
            this.ai = FIS.load(fclSchema, false).getFunctionBlock(fclBlockName);
            if (this.ai == null) {
                throw new PECodingException("Could not load the Fuzzy Control Language (FCL) specification from '"
                        + FCL_SCHEMA_FILE_NAME + "'");
            }
        } catch (final IOException | PEException e) {
            logger.error(e.getMessage(), e);
            throw new PECodingException(e);
        }
    }

    protected void setVariable(final FlvName name, final double value) {
        ai.setVariable(name.get(), value);
    }

    protected void setVariables(final Map<FlvName, Double> variables) {
        if (variables != null) {
            for (final Map.Entry<FlvName, Double> var : variables.entrySet()) {
                this.setVariable(var.getKey(), var.getValue());
            }
        }
    }

    protected void setRuleWeights(final Map<FlvName, Double> weights) {
        if (weights != null) {
            for (final Map.Entry<FlvName, Double> weight : weights.entrySet()) {
                this.setWeightOnRule(weight.getKey(), weight.getValue());
            }
        }
    }

    /**
     * Set a given weight on all rules named 'prefix_*'.
     * 
     * @param ruleWeight
     *            A number from interval [0.0, 1.0] or 1.0 if null.
     */
    protected void setWeightOnRule(final FlvName ruleNamePrefix, final Double ruleWeight) {
        final double weight = (ruleWeight != null) ? ruleWeight : DEFAULT_RULE_WEIGHT;
        if (!VALID_RULE_WEIGHT_RANGE.containsDouble(weight)) {
            throw new PECodingException(
                    "Weight (" + weight + ") for rule(s) '" + ruleNamePrefix + "*' is out of range.");
        }

        for (final Rule rule : this.ai.getFuzzyRuleBlock(null).getRules()) {
            if (rule.getName().startsWith(ruleNamePrefix.get().concat(RULE_NAME_PREFIX_SEPARATOR))) {
                rule.setWeight(weight);
            }
        }
    }

    public void evaluate() {
        ai.evaluate();
    }

    public double getScore() {
        return this.getVariable(Variables.SCORE_FLV_NAME).getLatestDefuzzifiedValue();
    }

    public double getVariableValue(final FlvName name) {
        return this.getVariable(name).getValue();
    }

    private Variable getVariable(final FlvName name) {
        return this.ai.getVariable(name.get());
    }

    @Override
    public String toString() {
        final StringBuilder value = new StringBuilder();
        return value.append(this.getFlvName()).append(" (")
                .append(MathUtils.round(this.getScore(), AiTemplateBuilder.NUMBER_DISPLAY_PRECISION)).append(")")
                .toString();
    }

    /**
     * Name of the associated Function Block in the FCL file.
     */
    protected abstract String getFclName();

    /**
     * Name of this FLV object.
     */
    protected abstract String getFlvName();
}