/*
 * @(#)FC.java    2.4.0   7 July 2005
 *
 * Copyright 2005
 * College of Computer and Information Science
 * Northeastern University
 * Boston, MA  02115
 *
 * The Java Power Tools software may be used for educational
 * purposes as long as this copyright notice is retained intact
 * at the top of all source files.
 *
 * To discuss possible commercial use of this software, 
 * contact Richard Rasala at Northeastern University, 
 * College of Computer and Information Science,
 * 617-373-2462 or rasala@ccs.neu.edu.
 *
 * The Java Power Tools software has been designed and built
 * in collaboration with Viera Proulx and Jeff Raab.
 *
 * Should this software be modified, the words "Modified from 
 * Original" must be included as a comment below this notice.
 *
 * All publication rights are retained.  This software or its 
 * documentation may not be published in any media either
 * in whole or in part without explicit permission.
 *
 * This software was created with support from Northeastern 
 * University and from NSF grant DUE-9950829.
 */

package edu.neu.ccs;

import edu.neu.ccs.util.*;

/**
 * <p>Class <code>FC</code> is a collection of static methods
 * that make it easy to create and manipulate complex functions
 * of one argument, that is, objects that implement the interface
 * <code>FunctionComplex.OneArg</code>. Such function objects
 * must have a method of the form:</p>
 *
 * <p><code>public XComplex evaluate(XComplex x)</code></p>
 *
 * <p>Class <code>FC</code> cannot be instantiated.</p>
 *
 * @author  Richard Rasala
 * @version 2.4.0
 * @since   2.4.0
 */
public class FC {

    // Prevent instantiation
    private FC() {}
    
    
    /** The identity function x --> x. */
    public static final FunctionComplex.OneArg identity = new FunctionComplex.OneArg() {
        public XComplex evaluate(XComplex x) { return x; }
    };
    
    
    /** The function x --> exp(x). */
    public static final FunctionComplex.OneArg exp = new FunctionComplex.OneArg() {
        public XComplex evaluate(XComplex x) { return XComplex.exp(x); }
    };
    
    
    /** The function x --> log(x). */
    public static final FunctionComplex.OneArg log = new FunctionComplex.OneArg() {
        public XComplex evaluate(XComplex x) { return XComplex.log(x); }
    };
    
    
    /** The function x --> sqrt(x). */
    public static final FunctionComplex.OneArg sqrt = new FunctionComplex.OneArg() {
        public XComplex evaluate(XComplex x) { return XComplex.sqrt(x); }
    };
    
    
    /**
     * The constant function x --> c.
     *
     * @param c the constant.
     */
    public static FunctionComplex.OneArg constant(XComplex c) {
        final XComplex cc = new XComplex(c);
        
        return new FunctionComplex.OneArg() {
            public XComplex evaluate(XComplex x) { return cc; }
        };
    }
    
    
    /**
     * The scale function x --> a * x.
     *
     * @param a the scale.
     */
    public static FunctionComplex.OneArg scale(XComplex a) {
        final XComplex aa = new XComplex(a);
        
        return new FunctionComplex.OneArg() {
            public XComplex evaluate(XComplex x)
                { return XComplex.multiply(aa, x); }
        };
    }
    
    
    /**
     * The translate function x --> x + b.
     *
     * @param b the translate.
     */
    public static FunctionComplex.OneArg translate(XComplex b) {
        final XComplex bb = new XComplex(b);
        
        return new FunctionComplex.OneArg() {
            public XComplex evaluate(XComplex x)
                { return XComplex.add(x, bb); }
        };
    }
    
    
    /**
     * The linear function x --> a * x + b.
     *
     * @param a the scale.
     * @param b the translate.
     */
    public static FunctionComplex.OneArg linear(XComplex a, XComplex b) {
        final XComplex aa = new XComplex(a);
        final XComplex bb = new XComplex(b);
        
        return new FunctionComplex.OneArg() {
            public XComplex evaluate(XComplex x)
                { return XComplex.add(XComplex.multiply(aa, x), bb); }
        };
    }
    
    
    /**
     * The function x --> x-to-the-power-n
     * = <code>XComplex.power(x,n)</code>.
     */
    public static FunctionComplex.OneArg xToPowerN(final int n) {
        return new FunctionComplex.OneArg() {
            public XComplex evaluate(XComplex x)
                { return XComplex.power(x, n); }
        };
    }
    
    
    /**
     * The function x --> x-to-the-power-a
     * = <code>XComplex.generalPower(x,a)</code>.
     */
    public static FunctionComplex.OneArg xToPowerA(XComplex a) {
        final XComplex aa = new XComplex(a);
        
        return new FunctionComplex.OneArg() {
            public XComplex evaluate(XComplex x)
                { return XComplex.generalPower(x, aa); }
        };
    }
    
    
    /**
     * The function x --> a-to-the-power-x
     * = <code>XComplex.generalPower(a,x)</code>.
     */
    public static FunctionComplex.OneArg aToPowerX(XComplex a) {
        final XComplex aa = new XComplex(a);
        
        return new FunctionComplex.OneArg() {
            public XComplex evaluate(XComplex x)
                { return XComplex.generalPower(aa, x); }
        };
    }
    
    
    /** The function to add functions f,g: f + g. */
    public static FunctionComplex.OneArg add
        (final FunctionComplex.OneArg f, final FunctionComplex.OneArg g)
    {
        checkNull("add", f, g);
        
        return new FunctionComplex.OneArg() {
            public XComplex evaluate(XComplex x) {
                return XComplex.add(f.evaluate(x), g.evaluate(x));
            }
        };
    }
    
    
    /** The function to subtract functions f,g: f - g. */
    public static FunctionComplex.OneArg subtract
        (final FunctionComplex.OneArg f, final FunctionComplex.OneArg g)
    {
        checkNull("subtract", f, g);
        
        return new FunctionComplex.OneArg() {
            public XComplex evaluate(XComplex x) {
                return XComplex.subtract(f.evaluate(x), g.evaluate(x));
            }
        };
    }
    
    
    /** The function to multiply functions f,g: f * g. */
    public static FunctionComplex.OneArg multiply
        (final FunctionComplex.OneArg f, final FunctionComplex.OneArg g)
    {
        checkNull("multiply", f, g);
        
        return new FunctionComplex.OneArg() {
            public XComplex evaluate(XComplex x) {
                return XComplex.multiply(f.evaluate(x), g.evaluate(x));
            }
        };
    }
    
    
    /** The function to divide functions f,g: f / g. */
    public static FunctionComplex.OneArg divide
        (final FunctionComplex.OneArg f, final FunctionComplex.OneArg g)
    {
        checkNull("divide", f, g);
        
        return new FunctionComplex.OneArg() {
            public XComplex evaluate(XComplex x) {
                return XComplex.divide(f.evaluate(x), g.evaluate(x));
            }
        };
    }
    
    
    /** The function to compose functions f,g: x --> f(g(x)). */
    public static FunctionComplex.OneArg compose
        (final FunctionComplex.OneArg f, final FunctionComplex.OneArg g)
    {
        checkNull("compose", f, g);
        
        return new FunctionComplex.OneArg() {
            public XComplex evaluate(XComplex x) {
                return f.evaluate(g.evaluate(x));
            }
        };
    }
    
    
    /** The function to compute the function f-to-the-power-n. */
    public static FunctionComplex.OneArg power
        (final FunctionComplex.OneArg f, final int n)
    {
        checkNull("power", f);
        
        return new FunctionComplex.OneArg() {
            public XComplex evaluate(XComplex x) {
                return XComplex.power(f.evaluate(x), n);
            }
        };
    }
    
    
    /** The function to compute the function f-to-the-power-d. */
    public static FunctionComplex.OneArg generalPower
        (final FunctionComplex.OneArg f, final double d)
    {
        checkNull("generalPower", f);
        
        return new FunctionComplex.OneArg() {
            public XComplex evaluate(XComplex x) {
                return XComplex.generalPower(f.evaluate(x), d);
            }
        };
    }
    
    
    /** The function to compute the function f-to-the-power-z. */
    public static FunctionComplex.OneArg generalPower
        (final FunctionComplex.OneArg f, XComplex z)
    {
        checkNull("generalPower", f);
        
        final XComplex zz = new XComplex(z);
        
        return new FunctionComplex.OneArg() {
            public XComplex evaluate(XComplex x) {
                return XComplex.generalPower(f.evaluate(x), zz);
            }
        };
    }
    
    
    /** The function to compute the function z-to-the-power-f. */
    public static FunctionComplex.OneArg generalPower
        (XComplex z, final FunctionComplex.OneArg f)
    {
        checkNull("generalPower", f);
        
        final XComplex zz = new XComplex(z);
        
        return new FunctionComplex.OneArg() {
            public XComplex evaluate(XComplex x) {
                return XComplex.generalPower(zz, f.evaluate(x));
            }
        };
    }
    
    
    /** The function to compute the function f-to-the-power-g. */
    public static FunctionComplex.OneArg generalPower
        (final FunctionComplex.OneArg f, final FunctionComplex.OneArg g)
    {
        checkNull("generalPower", f, g);
        
        return new FunctionComplex.OneArg() {
            public XComplex evaluate(XComplex x) {
                return XComplex.generalPower(f.evaluate(x), g.evaluate(x));
            }
        };
    }
    
    
    /**
     * Check for <code>null</code> function arguments and throw a
     * <code>NullPointerException</code> if necessary.</p>
     *
     * @param method the string name of the method
     * @param f the function argument
     */
    private static void checkNull
        (String method, FunctionComplex.OneArg f)
    {
        if (f == null)
            throw new NullPointerException("Null function f in FC." + method);
    }
    
    
    /**
     * Check for <code>null</code> function arguments and throw a
     * <code>NullPointerException</code> if necessary.</p>
     *
     * @param method the string name of the method
     * @param f the first  function argument
     * @param g the second function argument
     */
    private static void checkNull
        (String method, FunctionComplex.OneArg f, FunctionComplex.OneArg g)
    {
        if (f == null)
            throw new NullPointerException("Null function f in FC." + method);
        
        if (g == null)
            throw new NullPointerException("Null function g in FC." + method);
    }
    
    
}
