Skip to content

Commit 01c0211

Browse files
committed
v.1.0.6 in progress
* make sure rank methods rank valid objects * some more static methods split in two eg toGray, fromGray
1 parent 8b676c9 commit 01c0211

18 files changed

+2585
-2523
lines changed

src/js/Abacus.js

+76-17
Original file line numberDiff line numberDiff line change
@@ -20005,6 +20005,7 @@ Tensor = Abacus.Tensor = Class(CombinatorialIterator, {
2000520005
add = Arithmetic.add, sub = Arithmetic.sub, mul = Arithmetic.mul,
2000620006
index = Arithmetic.O, J = Arithmetic.J, nd, i;
2000720007

20008+
if (!item) return J;
2000820009
if ("partial" === type)
2000920010
{
2001020011
index = Arithmetic.num(find($.data, item, true));
@@ -20017,14 +20018,22 @@ Tensor = Abacus.Tensor = Class(CombinatorialIterator, {
2001720018
if ("tuple" === type)
2001820019
{
2001920020
nd = n[0];
20020-
if (!nd) return J;
20021-
for (n=n[1],i=0; i<nd; i++) index = add(mul(index, n), item[i]);
20021+
if (!nd || nd !== item.length) return J;
20022+
for (n=n[1],i=0; i<nd; i++)
20023+
{
20024+
if (0 > item[i] || item[i] >= n) return J;
20025+
index = add(mul(index, n), item[i]);
20026+
}
2002220027
}
2002320028
else
2002420029
{
2002520030
nd = n.length;
20026-
if (!nd) return J;
20027-
for (i=0; i<nd; i++) index = add(mul(index, n[i]), item[i]);
20031+
if (!nd || nd !== item.length) return J;
20032+
for (i=0; i<nd; i++)
20033+
{
20034+
if (0 > item[i] || item[i] >= n[i]) return J;
20035+
index = add(mul(index, n[i]), item[i]);
20036+
}
2002820037
}
2002920038
}
2003020039

@@ -20089,6 +20098,14 @@ Tensor = Abacus.Tensor = Class(CombinatorialIterator, {
2008920098
dir = -1 === dir ? -1 : 1;
2009020099
return 0 > dir ? igray(new Array(item.length), item, n) : gray(new Array(item.length), item, n);
2009120100
}
20101+
,toGray: function(item, n) {
20102+
dir = -1 === dir ? -1 : 1;
20103+
return gray(new Array(item.length), item, n);
20104+
}
20105+
,fromGray: function(item, n) {
20106+
dir = -1 === dir ? -1 : 1;
20107+
return igray(new Array(item.length), item, n);
20108+
}
2009220109
,inversion: function(inv) {
2009320110
// assume inv is tensor component of dimensions: (1,2,..,n-1,n) in this order
2009420111
var i, n = inv.length, perm = n ? [0] : [];
@@ -20216,7 +20233,7 @@ Permutation = Abacus.Permutation = Class(CombinatorialIterator, {
2021620233
// random ordering for derangements / involutions / connecteds
2021720234
// is based on random generation, instead of random unranking
2021820235
$.rand = $.rand || {};
20219-
$.rand["involution"] = 1; $.rand["connected"] = 1;
20236+
$.rand["involution"] = 1;
2022020237
if ("multiset" === $.type)
2022120238
{
2022220239
$.multiplicity = is_array($.multiplicity) && $.multiplicity.length ? $.multiplicity.slice() : array($.dimension, 1, 0);
@@ -20438,21 +20455,33 @@ Permutation = Abacus.Permutation = Class(CombinatorialIterator, {
2043820455
I = Arithmetic.I, J = Arithmetic.J, N, M;
2043920456

2044020457
n = n || item.length;
20441-
if (!item || 0 > n) return J;
20458+
if (!item || 0 > n || n !== item.length) return J;
2044220459
if (0===n) return index;
2044320460

2044420461
item = klass.DUAL(item, n, $);
2044520462

2044620463
if ("cyclic"=== type)
2044720464
{
20448-
// O(1)
20449-
index = Arithmetic.num(item[0]);
20465+
// O(n)
20466+
ii = item[0];
20467+
for (i=0; i<n; i++)
20468+
{
20469+
x = item[(i+n-ii)%n];
20470+
if (x !== i) return J;
20471+
}
20472+
index = Arithmetic.num(ii);
2045020473
}
2045120474
else if ("connected" === type)
2045220475
{
2045320476
// O(nlgn)
2045420477
if (n === item.length)
2045520478
{
20479+
for (dict={},i=0; i<n; i++)
20480+
{
20481+
x = item[i];
20482+
if (0 > x || x >= n || 1 === dict[x]) return J;
20483+
dict[x] = 1;
20484+
}
2045620485
item = permutation2cycles(item)[0];
2045720486
if (n !== item.length) return J;
2045820487
k = item.indexOf(n-1);
@@ -20501,6 +20530,14 @@ Permutation = Abacus.Permutation = Class(CombinatorialIterator, {
2050120530
// adapted from https://github.com/WoDoInc/FindMultisetRank
2050220531
// O(nm) ~ O(n^2) TODO construct O(nlgn) algorithm
2050320532
M = $.multiplicity.slice();
20533+
for (i=0; i<n; i++)
20534+
{
20535+
x = item[i];
20536+
if (0 > x || x >= M.length || 0 >= M[x]) return J;
20537+
M[x]--;
20538+
}
20539+
if (0 !== M.filter(function(x){return x !== 0;}).length) return J;
20540+
M = $.multiplicity.slice();
2050420541
N = $ && null!=$.count ? $.count : factorial(n,M);
2050520542
for (m=n-1,i=0; i<m && Arithmetic.gt(N, I); i++)
2050620543
{
@@ -21217,20 +21254,25 @@ Combination = Abacus.Combination = Class(CombinatorialIterator, {
2121721254
,rank: function(item, n, $) {
2121821255
var klass = this, Arithmetic = Abacus.Arithmetic,
2121921256
add = Arithmetic.add, sub = Arithmetic.sub,
21220-
mul = Arithmetic.mul, O = Arithmetic.O, I = Arithmetic.I,
21221-
index = O, i, c, j, k = n[1], N, binom,
21257+
mul = Arithmetic.mul, O = Arithmetic.O, I = Arithmetic.I, J = Arithmetic.J,
21258+
index = O, i, c, j, k = n[1], N, binom, x, dict,
2122221259
order = $ && null!=$.order ? $.order : LEX,
2122321260
type = $ && $.type ? $.type : "combination"/*"unordered"*/;
2122421261

21225-
if (0 > n[0] || 0 > n[1]) return Arithmetic.J;
21262+
if (!item || 0 > n[0] || 0 > n[1] || k !== item.length) return J;
21263+
2122621264
if (0===k) return O;
2122721265
item = klass.DUAL(item, n, $);
2122821266

2122921267
if (("ordered+repeated" === type) || ("variation+repeated" === type) || ("repeated+variation" === type))
2123021268
{
2123121269
// O(k)
2123221270
N = n[0];
21233-
for (i=0; i<k; i++) index = add(mul(index, N), item[i]);
21271+
for (i=0; i<k; i++)
21272+
{
21273+
if (0 > item[i] || item[i] >= N) return J;
21274+
index = add(mul(index, N), item[i]);
21275+
}
2123421276
}
2123521277
else if (("repeated" === type) || ("combination+repeated" === type))
2123621278
{
@@ -21241,6 +21283,7 @@ Combination = Abacus.Combination = Class(CombinatorialIterator, {
2124121283
// "Algorithms for Unranking Combinations and Other Related Choice Functions", Zbigniew Kokosi´nski 1995 (http://riad.pk.edu.pl/~zk/pubs/95-1-006.pdf)
2124221284
// adjust the order to match MSB to LSB
2124321285
// reverse of wikipedia article http://en.wikipedia.org/wiki/Combinatorial_number_system
21286+
if (0 > item[i-1] || item[i-1] >= n[0] || (i<k && item[i-1] > item[i])) return J;
2124421287
c = N-1-item[i-1]-i+1; j = k+1-i;
2124521288
if (j <= c) index = add(index, factorial(c, j));
2124621289
}
@@ -21251,7 +21294,13 @@ Combination = Abacus.Combination = Class(CombinatorialIterator, {
2125121294
// "Efficient Algorithms to Rank and Unrank Permutations in Lexicographic Order", Blai Bonet (http://ldc.usb.ve/~bonet/reports/AAAI08-ws10-ranking.pdf)
2125221295
// rank(ordered) = rank(k-n-permutation)
2125321296
// O(klgk)
21254-
N = n[0]; item = permutation2inversion(null, item, N);
21297+
N = n[0];
21298+
for (dict={},i=0; i<k; i++)
21299+
{
21300+
if (0 > item[i] || item[i] >= N || 1 === dict[item[i]]) return J;
21301+
dict[item[i]] = 1;
21302+
}
21303+
item = permutation2inversion(null, item, N);
2125521304
for (i=0; i<k; i++) index = add(mul(index, N-i), item[ i ]);
2125621305
}
2125721306
else//if (("combination" === type) || ("unordered" === type) || ("binary" === type))
@@ -21264,6 +21313,7 @@ Combination = Abacus.Combination = Class(CombinatorialIterator, {
2126421313
// "Algorithms for Unranking Combinations and Other Related Choice Functions", Zbigniew Kokosi´nski 1995 (http://riad.pk.edu.pl/~zk/pubs/95-1-006.pdf)
2126521314
// adjust the order to match MSB to LSB
2126621315
// reverse of wikipedia article http://en.wikipedia.org/wiki/Combinatorial_number_system
21316+
if (0 > item[i-1] || item[i-1] >= N || (i<k && item[i-1] >= item[i])) return J;
2126721317
c = N-1-item[i-1]; j = k+1-i;
2126821318
if (j <= c) index = add(index, factorial(c, j));
2126921319
}
@@ -21358,6 +21408,12 @@ Combination = Abacus.Combination = Class(CombinatorialIterator, {
2135821408
,binary: function(item, n, dir) {
2135921409
return -1 === dir ? binary2subset(item, n) : subset2binary(item, n);
2136021410
}
21411+
,toBinary: function(item, n) {
21412+
return subset2binary(item, n);
21413+
}
21414+
,fromBinary: function(item, n) {
21415+
return binary2subset(item, n);
21416+
}
2136121417
,pick: function(a, k, type) {
2136221418
return (0 < k) && a.length ? pick(a, k, ("ordered+repeated"!==type)&&("variation+repeated"!==type)&&("repeated+variation"!==type)&&("ordered"!==type)&&("variation"!==type), ("ordered+repeated"===type)||("variation+repeated"===type)||("repeated"===type)||("combination+repeated"===type), new Array(k)) : [];
2136321419
}
@@ -21764,6 +21820,7 @@ Subset = Abacus.Powerset = Abacus.Subset = Class(CombinatorialIterator, {
2176421820
{
2176521821
item = (is_binary && !is_reflected) || (is_reflected && !is_binary) ? item.slice(n-item[n],n) : item.slice(0,item[n]);
2176621822
}
21823+
if ($.mindimension > item.length || $.maxdimension < item.length) return J;
2176721824
if (0 === n)
2176821825
{
2176921826
index = O;
@@ -22632,6 +22689,8 @@ Partition = Abacus.Partition = Class(CombinatorialIterator, {
2263222689
{
2263322690
item = REFLECTED & order ? item.slice(LEN-item[LEN][0],LEN) : item.slice(0,item[LEN][0]);
2263422691
}
22692+
if ($.mindimension > item.length || $.maxdimension < item.length) return J;
22693+
2263522694
//if (REFLECTED & order) item = item.slice().reverse();
2263622695
item = klass.DUAL(item.slice(), n, $, -1);
2263722696

@@ -22643,7 +22702,7 @@ Partition = Abacus.Partition = Class(CombinatorialIterator, {
2264322702
index = O;
2264422703
if (W && M === W)
2264522704
{
22646-
return null == K || stdMath.floor(n/M) === K ? O : J;
22705+
return (null == K || n === K*M) && 0 === item.filter(function(x){return x !== M;}).length ? O : J;
2264722706
}
2264822707
for (w=0,m=0,i=0; 0<n && i<item.length; i++)
2264922708
{
@@ -22654,15 +22713,15 @@ Partition = Abacus.Partition = Class(CombinatorialIterator, {
2265422713
if (M === x) m++;
2265522714
n -= x;
2265622715
}
22657-
if (0 !== n) return J;
22716+
if (0 !== n || i !== item.length) return J;
2265822717
if (REVERSED & order) index = Arithmetic.sub(last, index);
2265922718
}
2266022719
else
2266122720
{
2266222721
index = last;
2266322722
if (W)
2266422723
{
22665-
if (M === W) return null == K || stdMath.floor(n/M) === K ? O : J;
22724+
if (M === W) return (null == K || n === K*M) && 0 === item.filter(function(x){return x !== M;}).length ? O : J;
2266622725
n -= W; if (K) K--;
2266722726
}
2266822727
for (i=0; 0<n && i<item.length; i++)
@@ -22673,7 +22732,7 @@ Partition = Abacus.Partition = Class(CombinatorialIterator, {
2267322732
index = Arithmetic.sub(index, M && 0 === i ? O : part_rank(n, x, W, M, K ? K-i : null));
2267422733
n -= x;
2267522734
}
22676-
if (0 !== n) return J;
22735+
if (0 !== n || i !== item.length) return J;
2267722736
if (!(REVERSED & order)) index = Arithmetic.sub(last, index);
2267822737
}
2267922738
}

src/js/Abacus.min.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/combinations.txt

+15-15
Original file line numberDiff line numberDiff line change
@@ -159,28 +159,28 @@ o.order("colex,reversed")
159159
0,1,3
160160
0,1,2
161161
o.order("random")
162-
2,4,5
163-
1,2,5
164-
0,1,3
165-
0,1,2
166-
0,2,5
167162
2,3,5
168-
0,4,5
169-
0,2,4
170163
0,1,4
171-
1,3,4
164+
2,3,4
165+
1,2,3
172166
1,2,4
167+
1,4,5
168+
0,2,5
169+
0,1,3
170+
0,3,4
171+
2,4,5
172+
1,3,4
173+
1,2,5
173174
0,2,3
174-
0,1,5
175-
2,3,4
176175
0,3,5
177-
1,4,5
178-
3,4,5
176+
0,1,5
177+
0,2,4
179178
1,3,5
180-
0,3,4
181-
1,2,3
179+
3,4,5
180+
0,4,5
181+
0,1,2
182182
o.random()
183-
1,3,5
183+
1,3,4
184184
o.order("colex").range(-5, -1)
185185
2,3,5
186186
0,4,5

test/combinations_repeats.txt

+48-48
Original file line numberDiff line numberDiff line change
@@ -411,64 +411,64 @@ o.order("colex,reversed")
411411
0,0,1
412412
0,0,0
413413
o.order("random")
414-
0,2,5
415-
1,3,3
416-
2,4,4
417-
1,1,5
418-
1,2,4
419-
2,3,5
420-
1,2,5
421-
3,4,4
422-
4,4,4
423-
5,5,5
424-
0,4,5
425-
1,1,1
426-
2,3,4
427-
2,4,5
428-
3,5,5
429-
2,2,4
430-
2,3,3
431-
3,3,4
432-
0,0,2
433-
0,2,2
434-
0,1,5
435-
4,5,5
436-
0,5,5
437-
1,2,2
438-
3,3,5
439414
1,1,3
440-
0,1,4
441-
0,3,3
415+
0,3,5
416+
3,5,5
442417
3,3,3
443-
0,0,1
444-
3,4,5
445-
4,4,5
446-
0,0,4
447-
0,2,4
448-
2,5,5
449-
1,1,2
418+
2,3,5
450419
0,4,4
451-
0,2,3
420+
2,5,5
452421
0,0,0
453-
0,1,3
454-
0,0,3
455-
1,2,3
456-
0,3,5
457-
2,2,5
458-
0,3,4
459-
0,1,2
460-
0,1,1
461-
2,2,3
462-
2,2,2
422+
0,0,1
423+
0,2,4
463424
1,5,5
425+
1,3,5
426+
1,2,3
464427
1,4,5
465-
1,3,4
428+
2,3,4
429+
0,0,4
466430
1,4,4
431+
1,1,2
432+
4,5,5
433+
1,2,4
434+
0,3,3
435+
0,1,4
436+
0,0,3
437+
1,1,1
438+
0,2,3
439+
1,2,2
440+
0,5,5
441+
0,4,5
442+
0,2,5
443+
1,1,5
444+
2,4,4
467445
0,0,5
446+
0,3,4
447+
0,1,1
448+
0,2,2
449+
2,4,5
450+
0,1,2
468451
1,1,4
469-
1,3,5
452+
1,2,5
453+
0,0,2
454+
2,3,3
455+
0,1,5
456+
5,5,5
457+
3,3,4
458+
2,2,4
459+
0,1,3
460+
1,3,3
461+
1,3,4
462+
4,4,5
463+
4,4,4
464+
3,4,5
465+
3,4,4
466+
2,2,2
467+
2,2,5
468+
2,2,3
469+
3,3,5
470470
o.random()
471-
1,1,2
471+
1,3,3
472472
o.order("colex").range(-5, -1)
473473
1,5,5
474474
2,5,5

0 commit comments

Comments
 (0)