001/**
002 * BinomialCoef -- A class that represents a set of binomial coefficients of a specified
003 * size.
004 * 
005 * Copyright (C) 2011-2015, by Joseph A. Huwaldt. All rights reserved.
006 * 
007 * This library is free software; you can redistribute it and/or modify it under the terms
008 * of the GNU Lesser General Public License as published by the Free Software Foundation;
009 * either version 2 of the License, or (at your option) any later version.
010 * 
011 * This library is distributed in the hope that it will be useful, but WITHOUT ANY
012 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
013 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public License along with
016 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place -
017 * Suite 330, Boston, MA 02111-1307, USA. Or visit: http://www.gnu.org/licenses/lgpl.html
018 */
019package jahuwaldt.js.math;
020
021import jahuwaldt.js.util.SizedObject;
022import jahuwaldt.js.util.SizedObjectFactory;
023import javolution.lang.ValueType;
024import javolution.text.Text;
025import javolution.text.TextBuilder;
026
027/**
028 * <p>
029 * This class represents an immutable matrix of binomial coefficients (n/k) defined up to
030 * a specified maximum index.
031 * </p>
032 * <pre>
033 *     ( n )      n!
034 *     (   ) = --------   0 <= k <= n
035 *     ( k )   k!(n-k)!
036 * </pre>
037 * 
038 * <p> Reference: http://en.wikipedia.org/wiki/Binomial_coefficient</p>
039 *
040 * <p> Modified by: Joseph A. Huwaldt </p>
041 * 
042 * @author Joseph A. Huwaldt, Date: May 11, 2011
043 * @version October 16, 2015
044 */
045public final class BinomialCoef implements ValueType, SizedObject {
046
047    /**
048     * The coefficients are stored in the this matrix.
049     */
050    private final double[][] _coefs;
051
052    /**
053     * Returns a {@link BinomialCoef} instance holding the coefficients (at least) up to
054     * the specified size. The returned instance may be recycled and may contain more
055     * coefficients than the requested size.
056     *
057     * @param size the desired size to compute coefficients for:
058     *             <code>N = size - 1 ==> (N/N)</code> or <code>size = N + 1</code>.
059     * @return The binomial coefficient matrix having at least specified size.
060     */
061    public static BinomialCoef newInstance(int size) {
062        BinomialCoef M = FACTORY.object(size);
063        return M;
064    }
065
066    /**
067     * Return the size of the binomial coefficient matrix (the maximum binomial index
068     * value: (N/N)).
069     */
070    @Override
071    public int size() {
072        return _coefs.length;
073    }
074
075    /**
076     * Return the specified binomial coefficient (n / k)
077     *
078     * @param n The 1st index into the binomial coefficient matrix (n / k). Must be &lt;
079     *          size().
080     * @param k The 2nd index into the binomial coefficient matrix (n / k). Must be &lt;
081     *          size().
082     * @return The specified binomial coefficient as a double.
083     */
084    public double get(int n, int k) {
085        return _coefs[n][k];
086    }
087
088    /**
089     * Returns a copy of this binomial coefficient matrix
090     * {@link javolution.context.AllocatorContext allocated} by the calling thread
091     * (possibly on the stack).
092     *
093     * @return an identical and independent copy of this binomial coefficient matrix.
094     */
095    @Override
096    public BinomialCoef copy() {
097        return copyOf(this);
098    }
099
100    /**
101     * Recycles a <code>BinomialCoef</code> instance immediately (on the stack when
102     * executing in a StackContext).
103     */
104    public static void recycle(BinomialCoef instance) {
105        FACTORY.recycle(instance);
106    }
107
108    /**
109     * Returns the text representation of this binomial coefficient matrix.
110     *
111     * @return the text representation of this binomial coefficient matrix.
112     */
113    public Text toText() {
114        TextBuilder tmp = TextBuilder.newInstance();
115
116        tmp.append('{');
117        int size = size() + 1;
118        for (int i = 0; i < size; i++) {
119            tmp.append('{');
120            for (int j = 0; j < size; ++j) {
121                tmp.append(get(i, j));
122                if (j != size - 1)
123                    tmp.append(", ");
124            }
125            tmp.append('}');
126        }
127        tmp.append('}');
128
129        Text txt = tmp.toText();
130        TextBuilder.recycle(tmp);
131        return txt;
132    }
133
134    /**
135     * Method that actually allocates a new array and fills it with binomial coefficients.
136     */
137    private static double[][] binomial(int size) {
138        double[][] bin = new double[size][size];
139
140        // Setup the first line
141        @SuppressWarnings("MismatchedReadAndWriteOfArray")
142        double[] row0 = bin[0];
143        row0[0] = 1.0;
144        for (int k = 1; k < size; ++k)
145            row0[k] = 0.;
146
147        // Setup the other lines
148        for (int n = 0; n < size - 1; n++) {
149            @SuppressWarnings("MismatchedReadAndWriteOfArray")
150            double[] binnp1 = bin[n + 1];
151            binnp1[0] = 1.0;
152            double[] binn = bin[n];
153            for (int k = 1; k < size; k++) {
154                if (n + 1 < k)
155                    binn[k] = 0.0;
156                else
157                    binnp1[k] = binn[k] + binn[k - 1];
158            }
159        }
160        return bin;
161    }
162
163    ///////////////////////
164    // Factory creation. //
165    ///////////////////////
166    @SuppressWarnings("unchecked")
167    private static SizedObjectFactory<BinomialCoef> FACTORY = new SizedObjectFactory<BinomialCoef>() {
168        @Override
169        protected BinomialCoef create(int size) {
170            BinomialCoef M = new BinomialCoef(size);
171            return M;
172        }
173    };
174
175    @SuppressWarnings("unchecked")
176    private static BinomialCoef copyOf(BinomialCoef original) {
177        int size = original.size();
178        BinomialCoef M = BinomialCoef.newInstance(size);
179        return M;
180    }
181
182    private BinomialCoef() {
183        _coefs = null;
184    }
185
186    private BinomialCoef(int size) {
187        _coefs = binomial(size);
188    }
189
190}