Skip to content

Commit

Permalink
v.0.8.0
Browse files Browse the repository at this point in the history
* rank/unrank multiset permutations (TODO nlgn algorithm)
* integer (restricted) compositions (rank/unrank missing)
* integer (restricted) partitions (rank/unrank missing)
* random partition / random composition
* successror methods support combinatorial orderings (LEX, COLEX, REFLECTED, ..) directly instead of post-transformations on objects
* optimise counting routines, list routiners, numeric routines (eg is_kthroot)
* new combinatorial utilities eg multiset2permutation, permutation2multiset
* fixed index/rank computation of composed combinatorial objects eg permutations or combinations and hasNext/hasPrev
* default to random generation if default Arithmetic and counter has overflowed
* fix some typos, wrong computations, indexes, ..
* update live playground example
  • Loading branch information
Nikos M committed Jan 26, 2017
1 parent 7538088 commit b21d869
Show file tree
Hide file tree
Showing 26 changed files with 3,259 additions and 3,238 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ A combinatorics library for Node/XPCOM/JS, PHP, Python, C/C++, Java
(php/python/java/c implementations in progress)


**version 0.8.0, in progress** (~ 48kB minified, ~ 15kB zipped)
**version 0.8.0** (~ 49kB minified, ~ 16kB zipped)

![abacus combinatorial numbers](/abacus.jpg)

Expand Down Expand Up @@ -563,7 +563,7 @@ o.dispose()
* support **multiple combined custom iterator orderings**, i.e `lex`, `colex`, `reversed`, `reflected`, `random` seamlessly and uniformly, both forward and backward [DONE, `random` ordering may be optimised further]
* support **efficient successor methods** (preferably `CAT/Loopless` methods) to generate next/prev object from current object [DONE]
* support **efficient ranking / unranking algorithms** and associated methods (preferably of `O(n)` or `O(nlgn)` complexity) for supported orderings [DONE]
* support multiple combinatorial orderings (ie `lex`, `colex`, `reflex`, `refcolex`, `minimal`, ..) **directly in the successor methods** instead of using post-transformations on object [ALMOST DONE, in progress]
* support multiple combinatorial orderings (ie `lex`, `colex`, `reflex`, `refcolex`, `minimal`, ..) **directly in the successor methods** instead of using post-transformations on object [DONE]
* support **unique and uniform random ordering traversals** for all combinatorial objects, so that the space of a combinatorial object can be traversed in **any random ordering uniquely and unbiasedly** (useful in some applications, eg backtracking) [DONE, see reference, used as custom iterator ordering, see above, may be optimised further]
* make sure the `.random` methods **uniformly and unbiasedly sample the combinatorial object space** (methods use unbiased sampling algorithms, however results in certain cases might depend on [quality of PRNGs](http://www0.cs.ucl.ac.uk/staff/d.jones/GoodPracticeRNG.pdf)) [DONE]
* support algebraic composition/cascading of combinatorial objects (of **fixed** dimensions at present) to construct new combinatorial objects (eg `all combinations` = `all permutations` **OF** `all unique combinations`) [DONE]
Expand Down
131 changes: 78 additions & 53 deletions src/js/Abacus.js
Original file line number Diff line number Diff line change
Expand Up @@ -706,9 +706,9 @@ function partitions( n, K /*exactly K parts or null*/, M /*max part is M or null
if ( null == partitions.mem[key] )
{
partitions.mem[key] = operate(function(p, k){
return add(p, operate(function(pk, m){
return operate(function(pk, m){
return add(pk, p_nkab(n, k, 1, m));
}, p, null, m1, m0?m0:n-k+1, 1));
}, p, null, m1, m0?m0:n-k+1, 1);
}, p, null, k0, k1, 1);
}
return partitions.mem[key];
Expand Down Expand Up @@ -3320,7 +3320,7 @@ function comb_item_( item, n, k, order, type )
function next_combination( item, N, dir, type, order, CI )
{
//maybe "use asm"
var k = N[1], n = N[0], i, j, index, curr, i0, DI, MIN, MAX, a, b, da, db;
var k = N[1], n = N[0], i, j, index, curr, i0, DI, MIN, MAX, a, b, da, db, inc, repeated;

// some C-P-T dualities, symmetries & processes at play here
// LEX
Expand Down Expand Up @@ -3399,30 +3399,47 @@ function next_combination( item, N, dir, type, order, CI )
}
else//if ( ("unordered" === type) || ("repeated" === type) )
{
// IN PROGRESS, does not work for COLEX
if ( COLEX&order )
repeated = "repeated" === type; inc = repeated ? 0 : 1;
if ( COLEX & order )
{
for(CI=[i0],i=MAX-i0; MIN<=i && i<=MAX; i+=DI) if( item[i]+DI < item[i+DI] ){ CI[0]=i; break; }
DI = -DI; i0 = MAX-i0; da = -da; db = MAX-db; i = MAX-i0;
j = 0 > DI ? MIN : MAX;
if ( (!repeated && item[j]+1>k) || (repeated && item[j]>0) )
{
if ( repeated ) while(MIN<=i && i<=MAX && 0===item[i] ) i+=DI;
else while(MIN<=i && i<=MAX && da*i+db===item[i] ) i+=DI;
item[i]-=1; i-=DI;
// attach rest of low block:
while(MIN<=i && i<=MAX) { item[i] = item[i+DI]-inc; i-=DI; }
}
else item = null;
}
else
{
for(CI=[i0],i=i0; MIN<=i && i<=MAX; i-=DI) if( item[i]+k<n+da*i+db ){ CI[0]=i; break; }
}
index = CI[0]; curr = item[index]+a;
j = "repeated" === type ? n-1 : n-k+da*index+db;
if ( a*curr+b === j )
{
item[index] = curr;
CI[0] = index-DI;
}
else if ( 0 < DI*(j-a*curr+b) )
{
if ( "repeated" === type ) a = 0;
for(i=index; MIN<=i && i<=MAX; i+=DI) { item[i]=curr; curr+=a; }
CI[0] = 0 > DI ? MIN : MAX;
/*if ( null == CI )
{*/
for(index=-1,i=i0; MIN<=i-DI && i-DI<=MAX; i-=DI)
if ( item[i]>item[i-DI]+inc ) { index = i; break; }
/*}
else
{
index = CI[0];
}*/
if (!(MIN<=index && index<=MAX) && 0 < item[0>DI?MAX:MIN]) index = 0>DI?MAX:MIN;
// adjust next indexes after the moved index
if ( MIN<=index && index<=MAX )
{
curr = n-1+inc;
for (i=i0; MIN<=i && i<=MAX && 0<DI*(i-index); i-=DI)
{
curr -= inc;
item[i] = curr;
}
item[index]--;
//if ( CI ) CI[0] = index+DI;
}
else item = null;
}
//else last item
else item = null;
}
}
else
Expand Down Expand Up @@ -3474,48 +3491,56 @@ function next_combination( item, N, dir, type, order, CI )
}
else//if ( ("unordered" === type) || ("repeated" === type) )
{
// IN PROGRESS, does not work for COLEX
a = "repeated" === type ? 0 : 1;
if ( COLEX&order )
{
for(CI=[i0],i=MAX-i0; MIN<=i && i<=MAX; i+=DI) if( item[i]+DI < item[i+DI] ){ CI[0]=i; break; }
}
else
{
for(CI=[i0],i=i0; MIN<=i && i<=MAX; i-=DI) if( item[i]+k<n+da*i+db ){ CI[0]=i; break; }
}
repeated = "repeated" === type; inc = repeated ? 0 : 1;
if ( COLEX & order )
{
if ( n === item[i0]+k )
{
// last
item = null;
}
else
DI = -DI; i0 = MAX-i0; da = -da; db = MAX-db; i = MAX-i0;
if ( (!repeated && item[i]+k<n) || (repeated && item[i]+1<n) )
{
i = CI[0];
while( item[i]+da === item[i+da] )
curr = da*i+db;
while(MIN<=i+DI && i+DI<=MAX && item[i]+inc === item[i+DI] )
{
item[i]=i; i+=da;
item[i] = curr; i+=DI; curr += inc;
}
item[i]+=1;
}
else item = null;
}
else
{
index = CI[0]; curr = item[index]+1;
j = "repeated" === type ? n-1 : n-k+da*index+db;
if ( curr === j )
/*if ( null == CI )
{*/
if ( repeated )
{
for(index=-1,j=n-1,i=i0; MIN<=i && i<=MAX; i-=DI)
if ( item[i] < j ) { index = i; break; }
}
else
{
for(index=-1,j=n-k,i=i0; MIN<=i && i<=MAX; i-=DI)
if ( item[i] < j+da*i+db ) { index = i; break; }
}
/*}
else
{
item[index] = curr;
CI[0] = index-DI;
}
else if ( curr < j )
index = CI[0];
}*/
// adjust next indexes after the moved index
if ( MIN<=index && index<=MAX )
{
for(i=index; MIN<=i && i<=MAX; i+=DI) { item[i]=curr; curr+=a; }
CI[0] = i0;
curr = item[index]+1;
j = repeated ? n-1 : n-k+da*index+db;
if ( curr === j )
{
item[index] = curr;
//if ( CI ) CI[0] = index-DI;
}
else if ( curr < j )
{
for(i=index; MIN<=i && i<=MAX; i+=DI) { item[i]=curr; curr+=inc; }
//if ( CI ) CI[0] = i0;
}
}
//else last item
else item = null;
}
}
Expand Down Expand Up @@ -3998,8 +4023,8 @@ Partition = Abacus.Partition = Class(CombinatorialIterator, {
// TODO, get conjugate order for now
if ( K && !M ) item = conjugatepartition(item, dir);

if ( ($ && "constant"===$['length']) && (item.length < n) )
item = 0 > dir ? array(n-item.length, 0, 0).concat(item) : item.concat(array(n-item.length, 0, 0));
/*if ( ($ && "constant"===$['length']) && (item.length < n) )
item = 0 > dir ? array(n-item.length, 0, 0).concat(item) : item.concat(array(n-item.length, 0, 0));*/
if ( "packed" === type ) item = packpartition(item, dir);
}
return _item===item ? item.slice() : item;
Expand Down
8 changes: 4 additions & 4 deletions src/js/Abacus.min.js

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions test/combinations.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@ echo('---');
echo('o = Abacus.Combination(6,3)');
o = Abacus.Combination(6,3);

echo('o.dimension()');
echo(o.dimension());

echo('o.total()');
echo(o.total());

Expand Down Expand Up @@ -67,6 +64,9 @@ print_all( o.order("colex,reflected") );
echo('o.order("colex,reversed")');
print_all( o.order("colex,reversed") );

/*echo('o.order("colex,reversed,reflected")');
print_all( o.order("colex,reversed,reflected") );*/

echo('o.order("random")');
print_all( o.order("random") );

Expand Down
32 changes: 15 additions & 17 deletions test/combinations.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
Abacus.Combinations (VERSION = 0.7.5)
Abacus.Combinations (VERSION = 0.8.0)
---
o = Abacus.Combination(6,3)
o.dimension()
3
o.total()
20
o.next()
Expand Down Expand Up @@ -161,28 +159,28 @@ o.order("colex,reversed")
[ 0, 1, 3 ]
[ 0, 1, 2 ]
o.order("random")
[ 0, 1, 2 ]
[ 0, 4, 5 ]
[ 0, 2, 4 ]
[ 0, 2, 5 ]
[ 0, 3, 5 ]
[ 1, 3, 5 ]
[ 0, 2, 3 ]
[ 2, 4, 5 ]
[ 0, 3, 4 ]
[ 1, 2, 4 ]
[ 1, 2, 5 ]
[ 1, 2, 4 ]
[ 1, 2, 3 ]
[ 0, 2, 3 ]
[ 1, 3, 4 ]
[ 2, 3, 5 ]
[ 0, 2, 5 ]
[ 0, 1, 4 ]
[ 1, 4, 5 ]
[ 2, 3, 4 ]
[ 2, 3, 5 ]
[ 0, 3, 4 ]
[ 1, 4, 5 ]
[ 0, 1, 2 ]
[ 0, 1, 5 ]
[ 0, 1, 3 ]
[ 0, 4, 5 ]
[ 1, 3, 4 ]
[ 0, 2, 4 ]
[ 3, 4, 5 ]
[ 0, 1, 5 ]
[ 0, 3, 5 ]
[ 1, 3, 5 ]
o.random()
[ 0, 1, 5 ]
[ 3, 4, 5 ]
o.order("colex").range(-5, -1)
[ 2, 3, 5 ]
[ 0, 4, 5 ]
Expand Down
6 changes: 3 additions & 3 deletions test/combinations_repeats.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@ echo('---');
echo('o = Abacus.Combination(6,3,{type:"repeated"})');
o = Abacus.Combination(6,3,{type:"repeated"});

echo('o.dimension()');
echo(o.dimension());

echo('o.total()');
echo(o.total());

Expand Down Expand Up @@ -67,6 +64,9 @@ print_all( o.order("colex,reflected") );
echo('o.order("colex,reversed")');
print_all( o.order("colex,reversed") );

/*echo('o.order("colex,reversed,reflected")');
print_all( o.order("colex,reversed,reflected") );*/

echo('o.order("random")');
print_all( o.order("random") );

Expand Down
Loading

0 comments on commit b21d869

Please sign in to comment.