/*
 This file is part of the software framework JStatCom, 
 a library for building applications for data based analysis.

 Copyright (C) 2000-2005  Markus Kraetzig

 This library 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 2.1 of the
 License, or (at your option) any later version.

 This library 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 library; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 USA
 */

package com.jstatcom.parser;

import java.util.HashMap;
import java.util.Map;
import java.util.Stack;

import com.jstatcom.util.UMatrix;

/**
 * Enumeration of all functions that are used by CalcEngine. The
 * defined functions objects override
 * execute(int argNum, Stack argStack) to provide the respective
 * functionality. All functions get their arguments from a stack and put the
 * results back on the stack after successful computation.
 * 
 * @author Markus Kraetzig 
 */
public abstract class CalcFunctions {

    /**
     * The name of the function.
     */
    private final String name;

    /**
     * The Map containing all functions with a string as key.
     */
    private static final Map functionMap = new HashMap();

    /**
     * fracdiff(a, d), fractional differences of a.
     */
    public static final CalcFunctions FRACDIFF = new CalcFunctions("FRACDIFF") {

        public void execute(int argNum, Stack argStack) {
            if (argNum != 2)
                throw new IllegalArgumentException(
                        "Wrong number of arguments to fracdiff(a, d).");

            /* Assemble the result as a double[] */
            double[] dd = argStack.pop();
            if (dd.length != 1)
                throw new IllegalArgumentException(
                        "fracdiff(a, d) only takes scalar as 2nd argument.");

            double[] aa = argStack.pop();
            double[] result = UMatrix.fracdiff(aa, dd[0]);
            argStack.push(result);
        }
    };

    /**
     * sin(a), computes sinus function for all elements of an array.
     */
    public static final CalcFunctions SIN = new CalcFunctions("SIN") {

        public void execute(int argNum, Stack argStack) {
            if (argNum != 1)
                throw new IllegalArgumentException(
                        "Wrong number of arguments to sin(a).");

            /* Assemble the result as a double[] */
            double[] aa = argStack.pop();
            double[] result = new double[aa.length];
            for (int i = 0; i < aa.length; i++)
                result[i] = Math.sin(aa[i]);
            argStack.push(result);
        }
    };

    /**
     * cos(a), computes cosinus function for all elements of an array.
     */
    public static final CalcFunctions COS = new CalcFunctions("COS") {

        public void execute(int argNum, Stack argStack) {
            if (argNum != 1)
                throw new IllegalArgumentException(
                        "Wrong number of arguments to cos(a).");

            /* Assemble the result as a double[] */
            double[] aa = argStack.pop();
            double[] result = new double[aa.length];
            for (int i = 0; i < aa.length; i++)
                result[i] = Math.cos(aa[i]);
            argStack.push(result);
        }
    };

    /**
     * tan(a), computes tangens function for all elements of an array.
     */
    public static final CalcFunctions TAN = new CalcFunctions("TAN") {

        public void execute(int argNum, Stack argStack) {
            if (argNum != 1)
                throw new IllegalArgumentException(
                        "Wrong number of arguments to tan(a).");

            /* Assemble the result as a double[] */
            double[] aa = argStack.pop();
            double[] result = new double[aa.length];
            for (int i = 0; i < aa.length; i++)
                result[i] = Math.tan(aa[i]);
            argStack.push(result);
        }
    };

    /**
     * sqrt(a), computes square root for all elements of an array.
     */
    public static final CalcFunctions SQRT = new CalcFunctions("SQRT") {

        public void execute(int argNum, Stack argStack) {
            if (argNum != 1)
                throw new IllegalArgumentException(
                        "Wrong number of arguments to sqrt(a).");

            /* Assemble the result as a double[] */
            double[] aa = argStack.pop();
            double[] result = new double[aa.length];
            for (int i = 0; i < aa.length; i++)
                result[i] = Math.sqrt(aa[i]);
            argStack.push(result);
        }
    };

    /**
     * log(a), computes natural logarithm for all elements of an array. Fails,
     * if the array contains values smaller or equal to zero.
     */
    public static final CalcFunctions LOG = new CalcFunctions("LOG") {

        public void execute(int argNum, Stack argStack) {
            if (argNum != 1)
                throw new IllegalArgumentException(
                        "Wrong number of arguments to log(a).");

            /* Assemble the result as a double[] */
            double[] aa = argStack.pop();
            double[] result = new double[aa.length];
            for (int i = 0; i < aa.length; i++) {
                if (aa[i] <= 0)
                    throw new IllegalArgumentException("Element at index "
                            + (i + 1) + " <= 0 for log(a).");

                result[i] = Math.log(aa[i]);
            }
            argStack.push(result);
        }
    };

    /**
     * lagn(a,b), lags the array by b elements and fills the resulting free
     * slots with Double.NaN. Lagging means, that every element
     * i is replaced by the element in i-b. The
     * argument b can also be negative, which would result in a
     * forward shift.
     */
    public static final CalcFunctions LAGN = new CalcFunctions("LAGN") {

        public void execute(int argNum, Stack argStack) {
            if (argNum != 2)
                throw new IllegalArgumentException(
                        "Wrong number of arguments to lagn(a,b).");

            /* Assemble the result as a double[] */
            double[] bb = argStack.pop();
            double[] aa = argStack.pop();

            if (bb.length != 1)
                throw new IllegalArgumentException(
                        "lagn(a,b) only takes scalar as 2nd argument.");

            int lag = new Double(bb[0]).intValue();

            double[] result = new double[aa.length];
            for (int i = 0; i < aa.length; i++) {
                if (i - lag < 0 || i - lag > aa.length - 1)
                    result[i] = Double.NaN;
                else
                    result[i] = aa[i - lag];
            }
            argStack.push(result);
        }
    };

    /**
     * rows(a), gets the rows of an array.
     */
    public static final CalcFunctions ROWS = new CalcFunctions("ROWS") {

        public void execute(int argNum, Stack argStack) {
            if (argNum != 1)
                throw new IllegalArgumentException(
                        "Wrong number of arguments to rows(a).");

            /* Assemble the result as a double[] */
            double[] aa = argStack.pop();
            double[] result = new double[] { aa.length };
            argStack.push(result);

        }
    };

    /**
     * ones(a), creates an array of ones with dimension (a x 1).
     */
    public static final CalcFunctions ONES = new CalcFunctions("ONES") {

        public void execute(int argNum, Stack argStack) {
            if (argNum != 1)
                throw new IllegalArgumentException(
                        "Wrong number of arguments to ones(a).");

            /* Assemble the result as a double[] */
            double[] aa = argStack.pop();

            if (aa.length != 1 || aa[0] < 1)
                throw new IllegalArgumentException(
                        "ones(a) takes only scalar >=1 as argument.");

            int length = new Double(aa[0]).intValue();
            double[] result = new double[length];
            for (int i = 0; i < length; i++)
                result[i] = 1;
            argStack.push(result);
        }
    };

    /**
     * trend(a), creates an array of numbers incremented by 1 with dimension
     * (a x 1), starting from 1.
     */
    public static final CalcFunctions TREND = new CalcFunctions("TREND") {

        public void execute(int argNum, Stack argStack) {
            if (argNum != 1)
                throw new IllegalArgumentException(
                        "Wrong number of arguments to trend(a).");

            /* Assemble the result as a double[] */
            double[] aa = argStack.pop();

            if (aa.length != 1 || aa[0] < 1)
                throw new IllegalArgumentException(
                        "trend(a) takes only scalar >=1 as argument.");

            int length = new Double(aa[0]).intValue();
            double[] result = new double[length];
            for (int i = 0; i < length; i++)
                result[i] = i + 1;
            argStack.push(result);
        }
    };

    /**
     * rndn(a), creates an array of a random numbers between 0
     * and 1.
     */
    public static final CalcFunctions RNDN = new CalcFunctions("RNDN") {

        public void execute(int argNum, Stack argStack) {
            if (argNum != 1)
                throw new IllegalArgumentException(
                        "Wrong number of arguments to rndn(a).");

            /* Assemble the result as a double[] */
            double[] aa = argStack.pop();

            if (aa.length != 1 || aa[0] < 1)
                throw new IllegalArgumentException(
                        "rndn(a) takes only scalar >=1 as argument.");

            int length = new Double(aa[0]).intValue();
            double[] result = new double[length];
            for (int i = 0; i < length; i++)
                result[i] = Math.random();
            argStack.push(result);
        }
    };

    /**
     * sumc(a), computes the sum of all elements in an array.
     */
    public static final CalcFunctions SUMC = new CalcFunctions("SUMC") {

        public void execute(int argNum, Stack argStack) {
            if (argNum != 1)
                throw new IllegalArgumentException(
                        "Wrong number of arguments to sumc(a).");

            /* Assemble the result as a double[] */
            double[] aa = argStack.pop();

            double[] result = new double[1];
            for (int i = 0; i < aa.length; i++)
                result[0] += aa[i];
            argStack.push(result);
        }
    };

    /**
     * meanc(a), computes the mean of all elements in an array.
     */
    public static final CalcFunctions MEANC = new CalcFunctions("MEANC") {

        public void execute(int argNum, Stack argStack) {
            if (argNum != 1)
                throw new IllegalArgumentException(
                        "Wrong number of arguments to meanc(a).");

            /* Assemble the result as a double[] */
            double[] aa = argStack.pop();

            double[] result = new double[1];
            for (int i = 0; i < aa.length; i++)
                result[0] += aa[i];
            result[0] = result[0] / aa.length;
            argStack.push(result);
        }
    };

    /**
     * stdc(a), computes the standard deviation of all elements in an array.
     */
    public static final CalcFunctions STDC = new CalcFunctions("STDC") {

        public void execute(int argNum, Stack argStack) {
            if (argNum != 1)
                throw new IllegalArgumentException(
                        "Wrong number of arguments to stdc(a).");

            /* Assemble the result as a double[] */
            double[] aa = argStack.pop();

            double mean = 0;
            for (int i = 0; i < aa.length; i++)
                mean += aa[i];
            mean = mean / aa.length;

            double[] result = new double[1];
            for (int i = 0; i < aa.length; i++)
                result[0] += Math.pow((aa[i] - mean), 2);
            result[0] = Math.sqrt(result[0] / aa.length);
            argStack.push(result);
        }
    };

    /**
     * stand(a), creates a normalized version if the array by subtracting the
     * mean and dividing by the standard deviation.
     */
    public static final CalcFunctions STAND = new CalcFunctions("STAND") {

        public void execute(int argNum, Stack argStack) {
            if (argNum != 1)
                throw new IllegalArgumentException(
                        "Wrong number of arguments to stand(a).");

            /* Assemble the result as a double[] */
            double[] aa = argStack.pop();

            double mean = 0;
            for (int i = 0; i < aa.length; i++)
                mean += aa[i];
            mean = mean / aa.length;

            double std = 0;
            for (int i = 0; i < aa.length; i++)
                std += Math.pow((aa[i] - mean), 2);
            std = Math.sqrt(std / aa.length);

            double[] result = new double[aa.length];
            for (int i = 0; i < aa.length; i++)
                result[i] = (aa[i] - mean) / std;

            argStack.push(result);

        }
    };

    /**
     * reverse(a), reverses the order of an array, starting from observation T
     * to 1.
     */
    public static final CalcFunctions REVERSE = new CalcFunctions("REVERSE") {

        public void execute(int argNum, Stack argStack) {
            if (argNum != 1)
                throw new IllegalArgumentException(
                        "Wrong number of arguments to reverse(a).");

            /* Assemble the result as a double[] */
            double[] aa = argStack.pop();

            double[] result = new double[aa.length];
            for (int i = 0; i < aa.length; i++)
                result[i] = aa[aa.length - 1 - i];

            argStack.push(result);

        }
    };

    /**
     * min(a,b), returns an array with the minimum elements of a
     * and b for each row.
     */
    public static final CalcFunctions MIN = new CalcFunctions("MIN") {

        public void execute(int argNum, Stack argStack) {
            if (argNum != 2)
                throw new IllegalArgumentException(
                        "Wrong number of arguments to min(a,b).");

            /* Assemble the result as a double[] */
            double[] bb = argStack.pop();
            double[] aa = argStack.pop();
            double[] result = new double[getLength(aa, bb)];
            for (int i = 0; i < result.length; i++)
                result[i] = Math.min(((aa.length == 1) ? aa[0] : aa[i]),
                        ((bb.length == 1) ? bb[0] : bb[i]));
            argStack.push(result);
        }
    };

    /**
     * max(a,b), returns an array with the maximum elements of a
     * and b for each row.
     */
    public static final CalcFunctions MAX = new CalcFunctions("MAX") {

        public void execute(int argNum, Stack argStack) {
            if (argNum != 2)
                throw new IllegalArgumentException(
                        "Wrong number of arguments to max(a,b).");

            /* Assemble the result as a double[] */
            double[] bb = argStack.pop();
            double[] aa = argStack.pop();
            double[] result = new double[getLength(aa, bb)];
            for (int i = 0; i < result.length; i++)
                result[i] = Math.max(((aa.length == 1) ? aa[0] : aa[i]),
                        ((bb.length == 1) ? bb[0] : bb[i]));
            argStack.push(result);

        }
    };

    /**
     * Add a new EngineRunType by subclassing and overriding operate.
     */
    protected CalcFunctions(String newName) {
        this.name = newName.toLowerCase();
        functionMap.put(name, this);
    }

    /**
     * Executes a function specified with a name.
     * 
     * @param functionName
     *            a case insensitive String with the name of the function to
     *            call
     * @param argNum
     *            the number of arguments to the function
     * @param argStack
     *            the current Stack to store the input as well as the result
     * @throws IllegalArgumentException
     *             in case the function does not exist or the arguments are
     *             wrong
     */
    public static void callFunctionForName(String functionName, int argNum,
            Stack argStack) throws IllegalArgumentException {

        if (functionName == null)
            throw new IllegalArgumentException("Function name is null.");

        Object key = functionName.toLowerCase();

        if (!functionMap.containsKey(key))
            throw new IllegalArgumentException("Function \"" + functionName
                    + "\" is not defined.");

        functionMap.get(key).execute(argNum, argStack);

    }

    /**
     * Override prevention method to enforce a.equals(b) if and
     * only if a==b.
     * 
     * @param o
     *            object to compare with
     * @return true if equal, false otherwise
     */
    public final boolean equals(Object o) {
        return super.equals(o);
    }

    /**
     * This defines the operation that is actually carried out by the function.
     * The method must be overridden if you define a new function. Input
     * parameters as well as results are contained in the argStack.
     * 
     * @param argNum
     *            the number of arguments to the function
     * @param argStack
     *            the current Stack to store the input as well as the result
     */
    public abstract void execute(int argNum, Stack argStack);

    /**
     * Computes the correct length when 2 array are combined.
     * 
     * @param aa
     *            double array
     * @param bb
     *            double array
     * @return the length for the result array
     * @throws ParseException
     *             if (aa.length != bb.length) && (aa.length != 1) && (bb.length !=
     *             1)
     */
    public static int getLength(double[] aa, double[] bb)
            throws IllegalArgumentException {

        if (aa.length == bb.length)
            return aa.length;
        if (aa.length == 1 && bb.length > 1)
            return bb.length;
        if (bb.length == 1 && aa.length > 1)
            return aa.length;
        throw new IllegalArgumentException("Array dimensions do not fit.");
    }

    /**
     * Override prevention method invokes super method.
     * 
     * @return hash code
     */
    public final int hashCode() {
        return super.hashCode();
    }

    /**
     * Returns the name of the runtype, do not use for comparisons.
     */
    public final String toString() {
        return name;
    }
}
 

Ads help maintain this website.