org.lightjason.agentspeak.action.builtin.math.statistic.CCreateDistribution.java Source code

Java tutorial

Introduction

Here is the source code for org.lightjason.agentspeak.action.builtin.math.statistic.CCreateDistribution.java

Source

/*
 * @cond LICENSE
 * ######################################################################################
 * # LGPL License                                                                       #
 * #                                                                                    #
 * # This file is part of the LightJason AgentSpeak(L++)                                #
 * # Copyright (c) 2015-17, LightJason (info@lightjason.org)                            #
 * # This program is free software: you can redistribute it and/or modify               #
 * # it under the terms of the GNU Lesser 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 Lesser General Public License for more details.                                #
 * #                                                                                    #
 * # You should have received a copy of the GNU Lesser General Public License           #
 * # along with this program. If not, see http://www.gnu.org/licenses/                  #
 * ######################################################################################
 * @endcond
 */

package org.lightjason.agentspeak.action.builtin.math.statistic;

import org.apache.commons.math3.distribution.AbstractRealDistribution;
import org.apache.commons.math3.distribution.BetaDistribution;
import org.apache.commons.math3.distribution.CauchyDistribution;
import org.apache.commons.math3.distribution.ChiSquaredDistribution;
import org.apache.commons.math3.distribution.ExponentialDistribution;
import org.apache.commons.math3.distribution.FDistribution;
import org.apache.commons.math3.distribution.GammaDistribution;
import org.apache.commons.math3.distribution.GumbelDistribution;
import org.apache.commons.math3.distribution.LaplaceDistribution;
import org.apache.commons.math3.distribution.LevyDistribution;
import org.apache.commons.math3.distribution.LogNormalDistribution;
import org.apache.commons.math3.distribution.LogisticDistribution;
import org.apache.commons.math3.distribution.NakagamiDistribution;
import org.apache.commons.math3.distribution.NormalDistribution;
import org.apache.commons.math3.distribution.ParetoDistribution;
import org.apache.commons.math3.distribution.TDistribution;
import org.apache.commons.math3.distribution.TriangularDistribution;
import org.apache.commons.math3.distribution.UniformRealDistribution;
import org.apache.commons.math3.distribution.WeibullDistribution;
import org.apache.commons.math3.random.ISAACRandom;
import org.apache.commons.math3.random.JDKRandomGenerator;
import org.apache.commons.math3.random.MersenneTwister;
import org.apache.commons.math3.random.RandomGenerator;
import org.apache.commons.math3.random.SynchronizedRandomGenerator;
import org.apache.commons.math3.random.Well1024a;
import org.apache.commons.math3.random.Well19937a;
import org.apache.commons.math3.random.Well19937c;
import org.apache.commons.math3.random.Well44497a;
import org.apache.commons.math3.random.Well44497b;
import org.apache.commons.math3.random.Well512a;
import org.lightjason.agentspeak.action.builtin.IBuiltinAction;
import org.lightjason.agentspeak.error.CIllegalStateException;
import org.lightjason.agentspeak.language.CCommon;
import org.lightjason.agentspeak.language.CRawTerm;
import org.lightjason.agentspeak.language.ITerm;
import org.lightjason.agentspeak.language.execution.IContext;
import org.lightjason.agentspeak.language.fuzzy.CFuzzyValue;
import org.lightjason.agentspeak.language.fuzzy.IFuzzyValue;

import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
import java.util.AbstractMap;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * creates a distribution object.
 * The action creates a distribution objects, with an individual
 * pseudo-random generator and different distribution paramter,
 * the action never fails, the following distributions are supported
 * with the following number of numeric arguments
 *
 * + beta distribution with 2 arguments (\f$ \alpha \f$ and \f$ \beta \f$)
 * + cauchy distribution with 2 arguments (media and scale)
 * + chi-square distribution with 1 argument (degree off freedom)
 * + exponential distribution with 1 argument (mean)
 * + f distribution with 2 arguments (degrees of freedom, denominator degrees of freedom)
 * + gamma distribution with 2 arguments (shape and scale)
 * + gumble distribution with 2 arguments (\f$ \mu \f$ and \f$ \beta \f$)
 * + laplace distirbution with 2 arguments (\f$ \mu \f$ and \f$ \beta \f$)
 * + levy distirbution with 2 arguments (\f$ \mu \f$ and \f$ c \f$)
 * + logistic distirbution with 2 arguments (\f$ \mu \f$ and \f$ s \f$)
 * + lognormal distirbution with 2 arguments (scale and shape)
 * + nakagami distribution with 2 arguments (\f$ \mu \f$ and \f$ \omega \f$)
 * + normal distribution with 2 arguments (expected value, variance)
 * + pareto distribution with 2 arguments (scale and shape)
 * + t distribution with 1 argument (degrees of freedom)
 * + triangular distribution with 3 arguments (a, b, c)
 * + uniform distribution with 2 arguments (lower and upper)
 * + weibull distribution with 2 arguments (\f$ \alpha \f$ and \f$ \beta \f$)
 *
 * The following pseudo-random number generators are supported:
 *
 * + mersennetwister (default)
 * + synchronizedmersennetwister
 * + isaac
 * + synchronizedisaac
 * + internal
 * + synchronizedinternal
 * + well512a
 * + synchronizedwell512a
 * + well1024a
 * + synchronizedwell1024a
 * + well19937a
 * + synchronizedwell19937a
 * + well19937c
 * + synchronizedwell19937c
 * + well4449a
 * + synchronizedwell4449a
 * + well44497b
 * + synchronizedwell44497b
 *
 * @code [D1|D2] = math/statistic/createdistribution( "normal", 20, 10, ["beta", "isaac", [8, 12]] ); @endcode
 * @see https://en.wikipedia.org/wiki/Beta_distribution
 * @see https://en.wikipedia.org/wiki/Cauchy_distribution
 * @see https://en.wikipedia.org/wiki/Chi-squared_distribution
 * @see https://en.wikipedia.org/wiki/Exponential_distribution
 * @see https://en.wikipedia.org/wiki/F-distribution
 * @see https://en.wikipedia.org/wiki/Gamma_distribution
 * @see https://en.wikipedia.org/wiki/Gumbel_distribution
 * @see https://en.wikipedia.org/wiki/L%C3%A9vy_distribution
 * @see https://en.wikipedia.org/wiki/Logistic_distribution
 * @see https://en.wikipedia.org/wiki/Log-normal_distribution
 * @see https://en.wikipedia.org/wiki/Nakagami_distribution
 * @see https://en.wikipedia.org/wiki/Normal_distribution
 * @see https://en.wikipedia.org/wiki/Pareto_distribution
 * @see https://en.wikipedia.org/wiki/Student%27s_t-distribution
 * @see https://en.wikipedia.org/wiki/Triangular_distribution
 * @see https://en.wikipedia.org/wiki/Uniform_distribution_(continuous)
 * @see https://en.wikipedia.org/wiki/Weibull_distribution
 */
public final class CCreateDistribution extends IBuiltinAction {
    /**
     * serial id
     */
    private static final long serialVersionUID = 614460992147593598L;

    /**
     * ctor
     */
    public CCreateDistribution() {
        super(3);
    }

    @Nonnegative
    @Override
    public final int minimalArgumentNumber() {
        return 1;
    }

    @Nonnull
    @Override
    public final IFuzzyValue<Boolean> execute(final boolean p_parallel, @Nonnull final IContext p_context,
            @Nonnull final List<ITerm> p_argument, @Nonnull final List<ITerm> p_return) {
        final List<ITerm> l_arguments = CCommon.flatten(p_argument).collect(Collectors.toList());

        IntStream.range(0, l_arguments.size())
                .filter(i -> CCommon.rawvalueAssignableTo(l_arguments.get(i), String.class))
                .mapToObj(i -> new AbstractMap.SimpleImmutableEntry<>(i, l_arguments.get(i).<String>raw()))
                .filter(i -> EDistribution.exist(i.getValue()))
                .map(i -> new AbstractMap.SimpleImmutableEntry<>(i.getKey(), EDistribution.from(i.getValue())))
                .map(i -> {

                    // check if next argument to the distribution name a generator name
                    final int l_skip;
                    final EGenerator l_generator;

                    if ((i.getKey() < l_arguments.size() - 1)
                            && (CCommon.rawvalueAssignableTo(l_arguments.get(i.getKey() + 1), String.class))) {
                        l_skip = 1;
                        l_generator = EGenerator.from(l_arguments.get(i.getKey() + 1).<String>raw());
                    } else {
                        l_skip = 0;
                        l_generator = EGenerator.MERSENNETWISTER;
                    }

                    // generate distribution object, arguments after distribution are the initialize parameter
                    return i.getValue().get(l_generator.get(),
                            l_arguments.stream().skip(i.getKey() + 1 + l_skip)
                                    .limit(i.getValue().getArgumentNumber()).map(ITerm::<Number>raw)
                                    .mapToDouble(Number::doubleValue).toArray());

                }).map(CRawTerm::from).forEach(p_return::add);

        return CFuzzyValue.from(true);
    }

    /**
     * usable distributions
     */
    private enum EDistribution {
        BETA(2), CAUCHY(2), CHISQUARE(1), EXPONENTIAL(1), F(2), GAMMA(2), GUMBLE(2), LAPLACE(2), LEVY(2), LOGISTIC(
                2), LOGNORMAL(2), NAKAGAMI(2), NORMAL(2), PARETO(2), T(1), TRIANGULAR(3), UNIFORM(2), WEIBULL(2);

        /**
         * enum name list
         */
        private static final Set<String> NAMES = Collections.unmodifiableSet(Arrays.stream(EDistribution.values())
                .map(i -> i.name().toUpperCase(Locale.ROOT)).collect(Collectors.toSet()));

        /**
         * number of arguments
         */
        private final int m_arguments;

        /**
         * ctor
         *
         * @param p_arguments number of arguments
         */
        EDistribution(final int p_arguments) {
            m_arguments = p_arguments;
        }

        /**
         * additional factory
         *
         * @param p_value string
         * @return enum
         */
        @Nonnull
        public static EDistribution from(@Nonnull final String p_value) {
            return EDistribution.valueOf(p_value.trim().toUpperCase(Locale.ROOT));
        }

        /**
         * checks if a name exists within the enum
         *
         * @param p_value string name
         * @return exist boolean
         */
        public static boolean exist(@Nonnull final String p_value) {
            return NAMES.contains(p_value.trim().toUpperCase(Locale.ROOT));
        }

        /**
         * return number of arguments
         *
         * @return argument number
         */
        public final int getArgumentNumber() {
            return m_arguments;
        }

        /**
         * returns the distribution object
         *
         * @param p_generator random generator
         * @param p_arguments arguments
         * @return real distribution
         */
        @Nonnull
        public final AbstractRealDistribution get(@Nonnull final RandomGenerator p_generator,
                final double[] p_arguments) {
            switch (this) {
            case BETA:
                return new BetaDistribution(p_generator, p_arguments[0], p_arguments[1]);

            case CAUCHY:
                return new CauchyDistribution(p_generator, p_arguments[0], p_arguments[1]);

            case CHISQUARE:
                return new ChiSquaredDistribution(p_generator, p_arguments[0]);

            case EXPONENTIAL:
                return new ExponentialDistribution(p_generator, p_arguments[0]);

            case F:
                return new FDistribution(p_generator, p_arguments[0], p_arguments[1]);

            case GAMMA:
                return new GammaDistribution(p_generator, p_arguments[0], p_arguments[1]);

            case GUMBLE:
                return new GumbelDistribution(p_generator, p_arguments[0], p_arguments[1]);

            case LAPLACE:
                return new LaplaceDistribution(p_generator, p_arguments[0], p_arguments[1]);

            case LEVY:
                return new LevyDistribution(p_generator, p_arguments[0], p_arguments[1]);

            case LOGISTIC:
                return new LogisticDistribution(p_generator, p_arguments[0], p_arguments[1]);

            case LOGNORMAL:
                return new LogNormalDistribution(p_generator, p_arguments[0], p_arguments[1]);

            case NAKAGAMI:
                return new NakagamiDistribution(p_generator, p_arguments[0], p_arguments[1],
                        NakagamiDistribution.DEFAULT_INVERSE_ABSOLUTE_ACCURACY);

            case NORMAL:
                return new NormalDistribution(p_generator, p_arguments[0], p_arguments[1]);

            case PARETO:
                return new ParetoDistribution(p_generator, p_arguments[0], p_arguments[1]);

            case T:
                return new TDistribution(p_generator, p_arguments[0]);

            case TRIANGULAR:
                return new TriangularDistribution(p_generator, p_arguments[0], p_arguments[1], p_arguments[2]);

            case UNIFORM:
                return new UniformRealDistribution(p_generator, p_arguments[0], p_arguments[1]);

            case WEIBULL:
                return new WeibullDistribution(p_generator, p_arguments[0], p_arguments[1]);

            default:
                throw new CIllegalStateException(
                        org.lightjason.agentspeak.common.CCommon.languagestring(this, "unknown", this));
            }
        }
    }

    /**
     * number generator
     */
    private enum EGenerator {
        MERSENNETWISTER, SYNCHRONIZEDMERSENNETWISTER, ISAAC, SYNCHRONIZEDISAAC, INTERNAL, SYNCHRONIZEDINTERNAL, WELL512A, SYNCHRONIZEDWELL512A, WELL1024A, SYNCHRONIZEDWELL1024A, WELL19937A, SYNCHRONIZEDWELL19937A, WELL19937C, SYNCHRONIZEDWELL19937C, WELL4449A, SYNCHRONIZEDWELL4449A, WELL44497B, SYNCHRONIZEDWELL44497B;

        /**
         * additional factory
         *
         * @param p_value string
         * @return enum
         */
        @Nonnull
        public static EGenerator from(@Nonnull final String p_value) {
            return EGenerator.valueOf(p_value.trim().toUpperCase(Locale.ROOT));
        }

        /**
         * returns a number generator
         *
         * @return generator
         */
        @Nonnull
        public final RandomGenerator get() {
            switch (this) {
            case MERSENNETWISTER:
                return new MersenneTwister();

            case SYNCHRONIZEDMERSENNETWISTER:
                return new SynchronizedRandomGenerator(new MersenneTwister());

            case ISAAC:
                return new ISAACRandom();

            case SYNCHRONIZEDISAAC:
                return new SynchronizedRandomGenerator(new ISAACRandom());

            case INTERNAL:
                return new JDKRandomGenerator();

            case SYNCHRONIZEDINTERNAL:
                return new SynchronizedRandomGenerator(new JDKRandomGenerator());

            case WELL512A:
                return new Well512a();

            case SYNCHRONIZEDWELL512A:
                return new SynchronizedRandomGenerator(new Well512a());

            case WELL1024A:
                return new Well1024a();

            case SYNCHRONIZEDWELL1024A:
                return new SynchronizedRandomGenerator(new Well1024a());

            case WELL19937A:
                return new Well19937a();

            case SYNCHRONIZEDWELL19937A:
                return new SynchronizedRandomGenerator(new Well19937a());

            case WELL19937C:
                return new Well19937c();

            case SYNCHRONIZEDWELL19937C:
                return new SynchronizedRandomGenerator(new Well19937c());

            case WELL4449A:
                return new Well44497a();

            case SYNCHRONIZEDWELL4449A:
                return new SynchronizedRandomGenerator(new Well44497a());

            case WELL44497B:
                return new Well44497b();

            case SYNCHRONIZEDWELL44497B:
                return new SynchronizedRandomGenerator(new Well44497b());

            default:
                throw new CIllegalStateException(
                        org.lightjason.agentspeak.common.CCommon.languagestring(this, "unknown", this));
            }
        }
    }
}