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 < 079 * size(). 080 * @param k The 2nd index into the binomial coefficient matrix (n / k). Must be < 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}