1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 | (function(global) {
|
13 | 'use strict';
|
14 | if (global.Combinatorics) return;
|
15 |
|
16 | var P = function(m, n) {
|
17 | var t, p = 1;
|
18 | if (m < n) {
|
19 | t = m;
|
20 | m = n;
|
21 | n = t;
|
22 | }
|
23 | while (n--) p *= m--;
|
24 | return p;
|
25 | };
|
26 | var C = function(m, n) {
|
27 | return P(m, n) / P(n, n);
|
28 | };
|
29 | var factorial = function(n) {
|
30 | return P(n, n);
|
31 | };
|
32 | var factoradic = function(n, d) {
|
33 | var f = 1;
|
34 | if (!d) {
|
35 | for (d = 1; f < n; f *= ++d);
|
36 | if (f > n) f /= d--;
|
37 | } else {
|
38 | f = factorial(d);
|
39 | }
|
40 | var result = [0];
|
41 | for (; d; f /= d--) {
|
42 | result[d] = Math.floor(n / f);
|
43 | n %= f;
|
44 | }
|
45 | return result;
|
46 | };
|
47 |
|
48 | var addProperties = function(dst, src) {
|
49 | Object.keys(src).forEach(function(p) {
|
50 | Object.defineProperty(dst, p, {
|
51 | value: src[p]
|
52 | });
|
53 | });
|
54 | };
|
55 | var hideProperty = function(o, p) {
|
56 | Object.defineProperty(o, p, {
|
57 | writable: true
|
58 | });
|
59 | };
|
60 | var toArray = function(f) {
|
61 | var e, result = [];
|
62 | this.init();
|
63 | while (e = this.next()) result.push(f ? f(e) : e);
|
64 | this.init();
|
65 | return result;
|
66 | };
|
67 | var common = {
|
68 | toArray: toArray,
|
69 | map: toArray,
|
70 | forEach: function(f) {
|
71 | var e;
|
72 | this.init();
|
73 | while (e = this.next()) f(e);
|
74 | this.init();
|
75 | },
|
76 | filter: function(f) {
|
77 | var e, result = [];
|
78 | this.init();
|
79 | while (e = this.next()) if (f(e)) result.push(e);
|
80 | this.init();
|
81 | return result;
|
82 | }
|
83 |
|
84 | };
|
85 |
|
86 | var power = function(ary, fun) {
|
87 | if (ary.length > 32) throw new RangeError;
|
88 | var size = 1 << ary.length,
|
89 | sizeOf = function() {
|
90 | return size;
|
91 | },
|
92 | that = Object.create(ary.slice(), {
|
93 | length: {
|
94 | get: sizeOf
|
95 | }
|
96 | });
|
97 | hideProperty(that, 'index');
|
98 | addProperties(that, {
|
99 | valueOf: sizeOf,
|
100 | init: function() {
|
101 | that.index = 0;
|
102 | },
|
103 | nth: function(n) {
|
104 | if (n >= size) return;
|
105 | var i = 0,
|
106 | result = [];
|
107 | for (; n; n >>>= 1, i++) if (n & 1) result.push(this[i]);
|
108 | return result;
|
109 | },
|
110 | next: function() {
|
111 | return this.nth(this.index++);
|
112 | }
|
113 | });
|
114 | addProperties(that, common);
|
115 | that.init();
|
116 | return (typeof (fun) === 'function') ? that.map(fun) : that;
|
117 | };
|
118 |
|
119 | var nextIndex = function(n) {
|
120 | var smallest = n & -n,
|
121 | ripple = n + smallest,
|
122 | new_smallest = ripple & -ripple,
|
123 | ones = ((new_smallest / smallest) >> 1) - 1;
|
124 | return ripple | ones;
|
125 | };
|
126 | var combination = function(ary, nelem, fun) {
|
127 | if (ary.length > 32) throw new RangeError;
|
128 | if (!nelem) nelem = ary.length;
|
129 | if (nelem < 1) throw new RangeError;
|
130 | if (nelem > ary.length) throw new RangeError;
|
131 | var first = (1 << nelem) - 1,
|
132 | size = C(ary.length, nelem),
|
133 | maxIndex = 1 << ary.length,
|
134 | sizeOf = function() {
|
135 | return size;
|
136 | },
|
137 | that = Object.create(ary.slice(), {
|
138 | length: {
|
139 | get: sizeOf
|
140 | }
|
141 | });
|
142 | hideProperty(that, 'index');
|
143 | addProperties(that, {
|
144 | valueOf: sizeOf,
|
145 | init: function() {
|
146 | this.index = first;
|
147 | },
|
148 | next: function() {
|
149 | if (this.index >= maxIndex) return;
|
150 | var i = 0,
|
151 | n = this.index,
|
152 | result = [];
|
153 | for (; n; n >>>= 1, i++) if (n & 1) result.push(this[i]);
|
154 | this.index = nextIndex(this.index);
|
155 | return result;
|
156 | }
|
157 | });
|
158 | addProperties(that, common);
|
159 | that.init();
|
160 | return (typeof (fun) === 'function') ? that.map(fun) : that;
|
161 | };
|
162 |
|
163 | var _permutation = function(ary) {
|
164 | var that = ary.slice(),
|
165 | size = factorial(that.length);
|
166 | that.index = 0;
|
167 | that.next = function() {
|
168 | if (this.index >= size) return;
|
169 | var copy = this.slice(),
|
170 | digits = factoradic(this.index, this.length),
|
171 | result = [],
|
172 | i = this.length - 1;
|
173 | for (; i >= 0; --i) result.push(copy.splice(digits[i], 1)[0]);
|
174 | this.index++;
|
175 | return result;
|
176 | };
|
177 | return that;
|
178 | };
|
179 |
|
180 | var permutation = function(ary, nelem, fun) {
|
181 | if (!nelem) nelem = ary.length;
|
182 | if (nelem < 1) throw new RangeError;
|
183 | if (nelem > ary.length) throw new RangeError;
|
184 | var size = P(ary.length, nelem),
|
185 | sizeOf = function() {
|
186 | return size;
|
187 | },
|
188 | that = Object.create(ary.slice(), {
|
189 | length: {
|
190 | get: sizeOf
|
191 | }
|
192 | });
|
193 | hideProperty(that, 'cmb');
|
194 | hideProperty(that, 'per');
|
195 | addProperties(that, {
|
196 | valueOf: function() {
|
197 | return size;
|
198 | },
|
199 | init: function() {
|
200 | this.cmb = combination(ary, nelem);
|
201 | this.per = _permutation(this.cmb.next());
|
202 | },
|
203 | next: function() {
|
204 | var result = this.per.next();
|
205 | if (!result) {
|
206 | var cmb = this.cmb.next();
|
207 | if (!cmb) return;
|
208 | this.per = _permutation(cmb);
|
209 | return this.next();
|
210 | }
|
211 | return result;
|
212 | }
|
213 | });
|
214 | addProperties(that, common);
|
215 | that.init();
|
216 | return (typeof (fun) === 'function') ? that.map(fun) : that;
|
217 | };
|
218 |
|
219 | var arraySlice = Array.prototype.slice;
|
220 | var cartesianProduct = function() {
|
221 | if (!arguments.length) throw new RangeError;
|
222 | var args = arraySlice.call(arguments),
|
223 | size = args.reduce(function(p, a) {
|
224 | return p * a.length;
|
225 | }, 1),
|
226 | sizeOf = function() {
|
227 | return size;
|
228 | },
|
229 | dim = args.length,
|
230 | that = Object.create(args, {
|
231 | length: {
|
232 | get: sizeOf
|
233 | }
|
234 | });
|
235 | if (!size) throw new RangeError;
|
236 | hideProperty(that, 'index');
|
237 | addProperties(that, {
|
238 | valueOf: sizeOf,
|
239 | dim: dim,
|
240 | init: function() {
|
241 | this.index = 0;
|
242 | },
|
243 | get: function() {
|
244 | if (arguments.length !== this.length) return;
|
245 | var result = [],
|
246 | d = 0;
|
247 | for (; d < dim; d++) {
|
248 | var i = arguments[d];
|
249 | if (i >= this[d].length) return;
|
250 | result.push(this[d][i]);
|
251 | }
|
252 | return result;
|
253 | },
|
254 | nth: function(n) {
|
255 | var result = [],
|
256 | d = 0;
|
257 | for (; d < dim; d++) {
|
258 | var l = this[d].length;
|
259 | var i = n % l;
|
260 | result.push(this[d][i]);
|
261 | n -= i;
|
262 | n /= l;
|
263 | }
|
264 | return result;
|
265 | },
|
266 | next: function() {
|
267 | if (this.index >= size) return;
|
268 | var result = this.nth(this.index);
|
269 | this.index++;
|
270 | return result;
|
271 | }
|
272 | });
|
273 | addProperties(that, common);
|
274 | that.init();
|
275 | return that;
|
276 | };
|
277 |
|
278 | addProperties(global.Combinatorics = Object.create(null), {
|
279 | C: C,
|
280 | P: P,
|
281 | factorial: factorial,
|
282 | factoradic: factoradic,
|
283 | cartesianProduct: cartesianProduct,
|
284 | combination: combination,
|
285 | permutation: permutation,
|
286 | power: power
|
287 | });
|
288 | })(this);
|