/** * * Abacus * Combinatorics and Algebraic Number Theory Symbolic Computation library for Javascript * @version: 1.0.9 * https://github.com/foo123/Abacus **/ !function(root, name, factory){ "use strict"; if (('undefined'!==typeof Components)&&('object'===typeof Components.classes)&&('object'===typeof Components.classesByID)&&Components.utils&&('function'===typeof Components.utils['import'])) /* XPCOM */ (root.$deps = root.$deps||{}) && (root.EXPORTED_SYMBOLS = [name]) && (root[name] = root.$deps[name] = factory.call(root)); else if (('object'===typeof module)&&module.exports) /* CommonJS */ (module.$deps = module.$deps||{}) && (module.exports = module.$deps[name] = factory.call(root)); else if (('function'===typeof define)&&define.amd&&('function'===typeof require)&&('function'===typeof require.specified)&&require.specified(name) /*&& !require.defined(name)*/) /* AMD */ define(name,['module'],function(module){factory.moduleUri = module.uri; return factory.call(root);}); else if (!(name in root)) /* Browser/WebWorker/.. */ (root[name] = factory.call(root)||1)&&('function'===typeof(define))&&define.amd&&define(function(){return root[name];}); }( /* current root */ 'undefined' !== typeof self ? self : this, /* module name */ "Abacus", /* module factory */ function ModuleFactory__Abacus(undef){ "use strict"; var Abacus = {VERSION: "1.0.9"}, stdMath = Math, PROTO = 'prototype', CLASS = 'constructor' ,slice = Array[PROTO].slice, HAS = Object[PROTO].hasOwnProperty, toString = Object[PROTO].toString ,log2 = stdMath.log2 || function(x) { return stdMath.log(x) / stdMath.LN2; } ,trim_re = /^\s+|\s+$/g ,trim = String[PROTO].trim ? function(s){ return s.trim(); } : function(s){ return s.replace(trim_re, ''); } ,pos_re = /\[(\d+)\]/g, pos_test_re = /\[(\d+)\]/ ,in_set_re = /^\{(\d+(?:(?:\.\.\d+)?|(?:,\d+)*))\}$/, not_in_set_re = /^!\{(\d+(?:(?:\.\.\d+)?|(?:,\d+)*))\}$/ ,dec_pattern = /^(-)?(\d+)(\.(\d+)?(\[\d+\])?)?(e-?\d+)?$/ ,Obj = function(){ return Object.create(null); } ,Extend = Object.create, KEYS = Object.keys ,Merge = function Merge(/* args */) { var args = arguments, l = args.length, a, b, i, p; a = (l ? args[0] : {}) || {}; i = 1; while (i 0 ? new Array(n+1).join('0') + bs : bs; } function to_tex(s) { var p = String(s).split('_'); return p[0] + (p.length > 1 ? ('_{'+p[1]+'}') : ''); } function Tex(s) { return is_callable(s.toTex) ? s.toTex() : String(s); } // https://github.com/foo123/FnList.js function operate(F, F0, x, i0, i1, ik, strict) { var Fv = F0, i, ii, ikk, di, i0r, i00, i11, rem, last = null, x_array = x && (is_array(x) || is_args(x)); if (x_array) { if (null == i0) i0 = 0; if (null == i1) i1 = x.length-1; } if (null == ik) ik = i0 > i1 ? -1 : 1; if ((0 === ik) || (x_array && !x.length) || (0 >= stdMath.floor((i1-i0)/ik)+1)) return Fv; if (0 > ik) { // remove not reachable range (not multiple of step ik) rem = (i0-i1)%(-ik); if (rem) last = i1; i1 += rem; i00 = i1; i11 = i0; di = -1; ikk = -((-ik) << 4); } else { // remove not reachable range (not multiple of step ik) rem = (i1-i0)%ik; if (rem) last = i1; i1 -= rem; i00 = i0; i11 = i1; di = 1; ikk = (ik << 4); } // unroll the rest range mod 16 + remainder i0r = i0+ik*(stdMath.floor((i1-i0)/ik+1)&15); if (x_array) { i00 = stdMath.max(0,i00); i11 = stdMath.min(x.length-1,i11); for (i=i0; i00<=i && i<=i11 && 0 0 ? new Array(n) : [])); n = x.length; if ((0 < n) && (null != x0)) { xs = xs||0; var xk = x0; operate(is_callable(x0) ? function(x,xi,i){ x[i] = x0(i); return x; } : (x0 === +x0 ? function(x,xi,i){ x[i] = xk; xk += xs; return x; } : function(x,xi,i){ x[i] = x0; return x; }), x, x); } return x; } function pluck(b, a, k) { return operate(function(b, ai, i){ b[i] = ai[k]; return b; }, b, a); } function complementation(b, a, n, a0, a1) { if (null == a) return b; return operate(is_array(n) ? function(b, ai, i){ b[i] = n[i]-1-ai; return b; } : function(b, ai, i){ b[i] = n-1-ai; return b; }, b, a, a0, a1); } function reflection(b, a, n, a0, a1) { if (null == a) return b; if (null == a0) a0 = 0; if (null == a1) a1 = a.length-1; if (b!==a || a00 ? (ai + s) % n[i] : 0; s += n[i]-b[i]; return b; } : function(b, ai, i){ b[i] = (ai + s) % n; s += n-b[i]; return b; }, b, a, a0, a1); } function igray(b, a, n, a0, a1) { if (null == a) return b; var s = 0; return operate(is_array(n) ? function(b, ai, i){ b[i] = n[i]>0 ? (ai + s) % n[i] : 0; s += ai; return b; } : function(b, ai, i){ b[i] = (ai + s) % n; s += ai; return b; }, b, a, a0, a1); } /*function ngray(b, a, n, a0, a1) { // adapted from https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.119.1344&rep=rep1&type=pdf if (null == a) return b; var s = 0; return operate(is_array(n) ? function(b, ai, i){ b[i] = s & 1 ? (0 < n[i] ? n[i]-1-ai : 0) : ai; s += b[i]; return b; } : function(b, ai, i){ b[i] = s & 1 ? n-1-ai : ai; s += b[i]; return b; }, b, a, a0, a1); } function ingray(b, a, n, a0, a1) { // adapted from https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.119.1344&rep=rep1&type=pdf if (null == a) return b; var s = 0; return operate(is_array(n) ? function(b, ai, i){ b[i] = s & 1 ? (0 < n[i] ? n[i]-1-ai : 0) : ai; s += ai; return b; } : function(b, ai, i){ b[i] = s & 1 ? n-1-ai : ai; s += ai; return b; }, b, a, a0, a1); }*/ function grayn(n) { // adapted from https://en.wikipedia.org/wiki/Gray_code var Arithmetic = Abacus.Arithmetic; n = Arithmetic.num(n); return Arithmetic.xor(n, Arithmetic.shr(n, Arithmetic.I)); } function igrayn(n) { // adapted from https://en.wikipedia.org/wiki/Gray_code var Arithmetic = Abacus.Arithmetic, inv = Arithmetic.O; n = Arithmetic.num(n); // Taking xor until n becomes zero while (Arithmetic.gt(n, Arithmetic.O)) { inv = Arithmetic.xor(inv, n); n = Arithmetic.shr(n, Arithmetic.I); } return inv; } function shift(b, a, k, a0, a1) { if (null == a) return b; if (null == a1) a1 = a.length-1; if (null == a0) a0 = 0; return b!==a || 0!==k ? operate(function(b,ai,i){ b[i+k] = ai; return b; }, b, a, 0>k?a0:a1, 0>k?a1:a0, 0>k?1:-1) : b; } function fdiff/*finite_difference*/(b, a, c1, c0, a0, a1, b0, b1) { if (null == a) return null; if (null == c1) c1 = 1; if (null == c0) c0 = 0; if (null == a0) a0 = 0; if (null == a1) a1 = a.length-1; if (null == b0) b0 = a0; if (null == b1) b1 = a1; var d0 = 0, bk = b0 > b1 ? -1 : 1, bi = b0; return operate(function(b, ai, i){ ai=c0+c1*ai; b[bi] = ai-d0; d0 = ai; bi+=bk; return b; }, b, a, a0, a1); } function psum/*partial_sum*/(b, a, c1, c0, a0, a1, b0, b1) { if (null == a) return null; if (null == c1) c1 = 1; if (null == c0) c0 = 0; if (null == a0) a0 = 0; if (null == a1) a1 = a.length-1; if (null == b0) b0 = a0; if (null == b1) b1 = a1; var s = 0, bk = b0 > b1 ? -1 : 1, bi = b0; return operate(function(b, ai, i){ s+=ai; b[bi] = c0+c1*s; bi+=bk; return b; }, b, a, a0, a1); } function unique(a, a0, a1) { if (null == a0) a0 = 0; if (null == a1) a1 = a.length-1; var n = a1-a0+1, dict, key, uniq, ul; if (1 >= n) return 1 === n ? [a[a0]] : []; dict = Obj(); uniq = new Array(n); ul = 0; while (a0 <= a1) { key = String(a[a0]); if (!dict[key]) { uniq[ul++] = a[a0]; dict[key] = 1; } a0++; } // truncate if needed if (uniq.length > ul) uniq.length = ul; return uniq; } function intersection(comm, a, b, dir, a0, a1, b0, b1) { dir = -1 === dir ? -1 : 1; if (null == a0) a0 = 0; if (null == a1) a1 = a.length-1; if (null == b0) b0 = 0; if (null == b1) b1 = b.length-1; var ak = a0 > a1 ? -1 : 1, bk = b0 > b1 ? -1 : 1, al = ak*(a1-a0)+1, bl = bk*(b1-b0)+1, ai = a0, bi = b0, il = 0; if (null == comm) comm = new Array(stdMath.min(al,bl)); if (0 === comm.length) return comm; // O(min(al,bl)) // assume lists are already sorted ascending/descending (indepentantly) while ((0 <= ak*(a1-ai)) && (0 <= bk*(b1-bi))) { if ((1===dir && a[ai]b[bi])) { ai+=ak; } else if ((1===dir && a[ai]>b[bi]) || (-1===dir && a[ai] a1 ? -1 : 1, bk = b0 > b1 ? -1 : 1, al = ak*(a1-a0)+1, bl = bk*(b1-b0)+1, ai = a0, bi = b0, dl = 0; if (!b || !b.length) return a === +a ? array(a, a0, ak) : (a ? a.slice() : a); if (null == diff) diff = new Array(duplicates?2*al:al); // O(al) // assume lists are already sorted ascending/descending (independantly) if (a === +a) { while ((0 <= ak*(a1-ai)) && (0 <= bk*(b1-bi))) { if (ai === b[bi]) { if (duplicates) diff[dl++] = ai; ai+=ak; bi+=bk; } else if ((1===dir && ai>b[bi]) || (-1===dir && aib[bi])) { diff[dl++] = ai; ai+=ak; } } while (0 <= ak*(a1-ai)) { diff[dl++] = ai; ai+=ak; } } else { while ((0 <= ak*(a1-ai)) && (0 <= bk*(b1-bi))) { if (a[ai] === b[bi]) { if (duplicates) diff[dl++] = a[ai]; ai+=ak; bi+=bk; } else if ((1===dir && a[ai]>b[bi]) || (-1===dir && a[ai]b[bi])) { diff[dl++] = a[ ai ]; ai+=ak; } } while (0 <= ak*(a1-ai)) { diff[dl++] = a[ai]; ai+=ak; } } // truncate if needed if (dl < diff.length) diff.length = dl; return diff; } function multi_difference(diff, mult, a, b, a0, a1, b0, b1) { if (null == a0) a0 = 0; if (null == a1) a1 = a.length-1; if (null == b0) b0 = 0; if (null == b1) b1 = b ? b.length-1 : -1; var ak = a0 > a1 ? -1 : 1, bk = b0 > b1 ? -1 : 1, al = ak*(a1-a0)+1, bl = bk*(b1-b0)+1, ai = a0, bi = b0, dl = 0; if (!b || !b.length) return a ? a.slice() : a; if (null == diff) diff = new Array(al); // O(al) // assume lists are already sorted ascending/descending (independantly) while ((0 <= ak*(a1-ai)) && (0 <= bk*(b1-bi))) { if (a[ai] === b[bi]) { if (1 < mult[a[ai]]) { mult[a[ai]]--; } else { ai+=ak; bi+=bk; } } else if (a[ai]>b[bi]) { bi+=bk; } else//if (a[ai] a1 ? -1 : 1, bk = b0 > b1 ? -1 : 1, al = ak*(a1-a0)+1, bl = bk*(b1-b0)+1, ul = al+bl, ai = a0, bi = b0, ui = 0, last = null, with_duplicates = !unique; if (null == union) union = new Array(ul); if (0 === union.length) return inplace ? a : union; // O(al+bl) // assume lists are already sorted ascending/descending (independantly), even with duplicate values while ((0 <= ak*(a1-ai)) && (0 <= bk*(b1-bi))) { if (unique && ui) // handle any possible duplicates inside SAME list { if (a[ai] === last) { ai+=ak; continue; } else if (b[bi] === last) { bi+=bk; continue; } } if (indices) { if ((1===dir && a[ai][0]b[bi][0])) { union[ui++] = last=a[ai]; ai+=ak; } else if ((1===dir && a[ai][0]>b[bi][0]) || (-1===dir && a[ai][0]b[bi][1])) { union[ui++] = last=a[ai]; if (with_duplicates) union[ui++] = b[bi]; } else { union[ui++] = last=b[bi]; if (with_duplicates) union[ui++] = a[ai]; } ai+=ak; bi+=bk; } } else { if ((1===dir && a[ai]b[bi])) { union[ui++] = last=a[ai]; ai+=ak; } else if ((1===dir && a[ai]>b[bi]) || (-1===dir && a[ai]ak?a1:a0,ui=0; ui ai) { if (1 === d0) { i1 = i-1; break; } else if (0 === d0) d0 = -1; } ap = ai; } if (0 === d0) d0 = dir; if (-1 === i1) { i1 = a1; index[0] = i0; index[1] = i1; index[2] = d0; } else { i2 = i1+1; i3 = -1; for (ap=indices?a[i2][0]:a[i2],i=i2+1; i<=a1; i++) { ai = indices?a[i][0]:a[i]; if (ap < ai) { if (-1 === d1) { i3 = i-1; break; } else if (0 === d1) d1 = 1; } else if (ap > ai) { if (1 === d1) { i3 = i-1; break; } else if (0 === d1) d1 = -1; } ap = ai; } if (-1 === i3) i3 = a1; if (0 === d1) d1 = dir; index[0] = i0; index[1] = i1; index[2] = d0; index[3] = i2; index[4] = i3; index[5] = d1; } } function mergesort(a, dir, natural, indices, a0, a1) { // http://en.wikipedia.org/wiki/Merge_sort if (null == a0) a0 = 0; if (null == a1) a1 = a.length-1; if (!a.length) return a; var ak = a0 > a1 ? -1 : 1, N = ak*(a1-a0)+1; indices = true === indices; // in-place if (1 >= N) return indices ? (1 === N ? [a0] : []) : a; dir = -1 === dir ? -1 : 1; var logN = N, size = 1, size2 = 2, min = stdMath.min, aux = new Array(N), index, i0, i1, i0p, i1p; if (indices) { a = operate(function(b,ai,i){b[i-a0]=[ai,i]; return b;}, new Array(N), a, a0, a1, 1); a0 = 0; a1 = N-1; } if (true === natural) { // O(N) average, O(NlgN) worst case i0p = a0; i1p = -1; index = [-1,-1,0,-1,-1,0]; do { // find already sorted chunks // O(n) sortedrun(a, a0, a1, index, indices, dir); if (-1 === index[3]) { // already sorted, reflect if sorted reversely // O(n) if (dir !== index[2] && a0 < a1) reflection(a, a, 0/*dummy*/, a0, a1); i0 = a0; i1 = a1; } else { // merge partialy sorted chunks appropriately into one run // O(n) index[2] = dir!==index[2]?1:0; index[5] = dir!==index[5]?1:0; merge(aux, a, a, dir, index[2]?index[1]:index[0], index[2]?index[0]:index[1], index[5]?index[4]:index[3], index[5]?index[3]:index[4], indices, false, true); i0 = index[0]; i1 = index[4]; } // merge with the previous run // O(n) if (-1 !== i1p) merge(aux, a, a, dir, i0p, i1p, i0, i1, indices, false, true); // update starting point for next chunk i1p = i1; a0 = i1+1; } while (a0 <= a1); } else { // O(NlgN) while (0 < logN) { operate(function(_,j){ merge(aux, a, a, dir, a0+ak*j, a0+ak*(j+size-1), a0+ak*(j+size), a0+ak*min(j+size2-1, N-1), indices, false, true); }, null, null, 0, N-size-1, size2); size <<= 1; size2 <<= 1; logN >>= 1; } } return indices ? pluck(a, a, 1) : a; } function is_sorted(a, dir, a0, a1) { var i, ap, ai, n = a.length, N; if (null == a0) a0 = 0; if (null == a1) a1 = n-1; // O(n) if (null == dir || 0 === dir) { // findout if and how it is sorted dir = 0; for (ap=a[a0],i=a0+1; i<=a1; i++) { ai = a[i]; if (ap < ai) { if (-1 === dir) return 0; else if (0 === dir) dir = 1; } else if (ap > ai) { if (1 === dir) return 0; else if (0 === dir) dir = -1; } ap = ai; } return 0 === dir ? 1 : dir; } else { // check that it is sorted by dir dir = -1 === dir ? -1 : 1; if (a0 >= a1) return dir; if (-1 === dir) { // reverse sorted, descending for (ap=a[a0],i=a0+1; i<=a1; i++) { ai = a[i]; if (ap < ai) return 0; else ap = ai; } } else { // sorted, ascending for (ap=a[a0],i=a0+1; i<=a1; i++) { ai = a[i]; if (ap > ai) return 0; else ap = ai; } } return dir; } } function shuffle(a, connected, a0, a1) { // http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle // https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#Sattolo.27s_algorithm var rndInt = Abacus.Math.rndInt, N, offset = true === connected ? 1 : 0; // O(n) if (is_array(a0)) { if (1 < (N=a0.length)) operate(function(a){ if (offset < N--) { var perm = rndInt(0, N-offset), swap = a[ a0[N] ]; a[ a0[N] ] = a[ a0[perm] ]; a[ a0[perm] ] = swap; } return a; }, a, a0, 0, N-1); } else { if (null == a0) a0 = 0; if (null == a1) a1 = a.length-1; if (1 < (N=a1-a0+1)) operate(function(a){ if (offset < N--) { var perm = rndInt(0, N-offset), swap = a[ a0+N ]; a[ a0+N ] = a[ a0+perm ]; a[ a0+perm ] = swap; } return a; }, a, a, 0, N-1); } return a; } function pick(a, k, sorted, repeated, backup, a0, a1) { // http://stackoverflow.com/a/32035986/3591273 if (null == a0) a0 = 0; if (null == a1) a1 = a.length-1; var rndInt = Abacus.Math.rndInt, picked, i, selected, value, n = a1-a0+1; k = stdMath.min(k, n); sorted = true === sorted; picked = new Array(k); if (true === repeated) { n = n-1; for (i=0; i=0; i--) // O(k) times { selected = backup[ i ]; value = a[ a0+n ]; a[ a0+n ] = a[ a0+selected ]; a[ a0+selected ] = value; n++; } } if (sorted) mergesort(picked);// O(klogk) times, average/worst-case return picked; } function binarysearch(v, a, dir, a0, a1, eq, lt) { // binary search O(logn) eq = eq || function(a, b){return a==b;}; lt = lt || function(a, b){return ar || lt(v, a[l]) || lt(a[r], v)) return -1; else if ( eq(v, a[l])) return l; else if (eq(v, a[r])) return r; if (-1===dir) { while (l>>1); am = a[m]; if (eq(v, am)) return m; else if (lt(am, v)) r = m-1; else l = m+1; } } else { while (l>>1); am = a[m]; if (eq(v, am)) return m; else if (lt(v, am)) r = m-1; else l = m+1; } } return -1; } function bisect(list, item, dir, lo, hi, lt) { // binary search O(logn) for point of insertion (either left or right depending on dir) // adapted from python's c source code, module bisect // https://github.com/python/cpython/blob/master/Modules/_bisectmodule.c lt = lt || function(a, b){return a lo) return -1; if (-1===dir) { while (lo < hi) { mid = ((lo+hi)>>>1); litem = list[mid]; if (lt(litem, item)) lo = mid+1; else hi = mid; } } else { while (lo < hi) { mid = ((lo+hi)>>>1); litem = list[mid]; if (lt(item, litem)) hi = mid; else lo = mid+1; } } return lo; } function bitreverse(b, nbits) { b = +b; var r = b & 1; if (null == nbits) while (b >>= 1) { r <<= 1; r |= b & 1; } else while (--nbits) { r <<= 1; b >>= 1; r |= b & 1; } return r; } function is_mirror_image(x) { var i, j; if (is_array(x) || is_args(x)) { if (1 >= x.length) return true; for (i=0,j=x.length-1; i= x.length) return true; for (i=0,j=x.length-1; i i || 0 > j) return []; var L1 = 0 === i ? 0 : L[i-1][j], L2 = 0 === j ? 0 : L[i][j-1], out, lcs1, lcs2, visited; if (all) { if (eq(a[i], b[j])) { out = lcs_backtrack(L, a, b, i-1, j-1, eq, all); return out.length ? out.map(function(path){path.push([i, j]); return path;}) : [[[i, j]]]; } out = []; // NOTE: below different paths, may lead to same LCS nevertheless, unless filtering is used lcs1 = L1 >= L2 ? lcs_backtrack(L, a, b, i-1, j, eq, all) : []; lcs2 = L2 >= L1 ? lcs_backtrack(L, a, b, i, j-1, eq, all) : []; if (lcs1.length && lcs2.length) { visited = lcs1.reduce(function(visited, path){visited[lcs_key(path)] = 1; return visited;}, Obj()); lcs2 = lcs2.filter(function(path){return 1 !== visited[lcs_key(path)];}); } out.push.apply(out, lcs1); out.push.apply(out, lcs2); return out; } else { if (eq(a[i], b[j])) { out = lcs_backtrack(L, a, b, i-1, j-1, eq, all); out.push([i, j]); return out; } return L1 >= L2 ? lcs_backtrack(L, a, b, i-1, j, eq, all) : lcs_backtrack(L, a, b, i, j-1, eq, all); } } function lcs(a, b, contiguous, ret, eq) { var i, j, n = a.length, m = b.length, s, L, L1, L2, out, sizeOnly = 'size' === ret, all = 'all' === ret; if (!n || !m) return sizeOnly ? 0 : []; eq = eq || default_eq; if (contiguous) { // https://en.wikipedia.org/wiki/Longest_common_substring_problem // O(nm) s = 0; out = []; L = new Array(n); for (i=0; i s) { s = L[i][j]; if (!sizeOnly) out = [[i-s+1, i, j-s+1, j]]; } else if (all && L[i][j] === s) { out.push([i-s+1, i, j-s+1, j]); } } else { L[i][j] = 0; } } } } else { // https://en.wikipedia.org/wiki/Longest_common_subsequence_problem // O(nm) L = new Array(n); out = []; for (i=0; i>= 1; b = mulm(b, b, m); } } else { two = Arithmetic.II; while (!Arithmetic.equ(e, O)) { if (Arithmetic.equ(I, Arithmetic.mod(e, two))) pow = mulm(pow, b, m); e = Arithmetic.div(e, two); b = mulm(b, b, m); } } return pow; } function powsq(b, e) { // power, supports Exact Big Integer Arithmetic if plugged in // https://en.wikipedia.org/wiki/Exponentiation_by_squaring var Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, I = Arithmetic.I, N = Arithmetic.num, two, pow; //b = N(b); e = N(e); if (Arithmetic.gt(O, e)) return null; // does not support negative powers for integers else if (Arithmetic.equ(O, e)) return I; else if (Arithmetic.equ(I, e)) return b; pow = I; if (Arithmetic.isDefault() || Arithmetic.lte(e, MAX_DEFAULT)) { // use bitwise operators for usual (small integer) exponents e = Arithmetic.val(e); while (0 !== e) { if (e & 1) pow = Arithmetic.mul(pow, b); e >>= 1; b = Arithmetic.mul(b, b); } } else { two = Arithmetic.II; while (!Arithmetic.equ(O, e)) { if (Arithmetic.equ(I, Arithmetic.mod(e, two))) pow = Arithmetic.mul(pow, b); e = Arithmetic.div(e, two); b = Arithmetic.mul(b, b); } } return pow; } function isqrt(n) { // integer square root // https://en.wikipedia.org/wiki/Integer_square_root var Arithmetic = Abacus.Arithmetic, N = Arithmetic.num, O = Arithmetic.O, I = Arithmetic.I, start, end, mid, mid2, sqrt, two; //n = N(n); //n = Arithmetic.abs(n); if (Arithmetic.equ(n, O) || Arithmetic.equ(n, I)) return n; // for default arithmetic and numbers use built-in square root, floored if (Arithmetic.isDefault() || Arithmetic.lte(n, MAX_DEFAULT)) return Arithmetic.num(stdMath.floor(stdMath.sqrt(Arithmetic.val(n)))); two = Arithmetic.II; // Binary Search (O(logn)) start = I; end = Arithmetic.div(n, two); sqrt = start; while (Arithmetic.lte(start, end)) { mid = Arithmetic.div(Arithmetic.add(start, end), two); mid2 = Arithmetic.mul(mid, mid); if (Arithmetic.equ(mid2, n)) return mid; if (Arithmetic.lt(mid2, n)) { start = Arithmetic.add(mid, I); sqrt = mid; } else { end = Arithmetic.sub(mid, I); } } return sqrt; } function jskthroot(x, k) { var kg, r, p; k = +k; if (0 === k) return null; if (0 > k) { x = 1.0/x; k = -k; } if (1 === k) return x; kg = k & 1; if ((1===kg) && (0>x)) x = -x; r = stdMath.pow(x, 1.0/k); p = stdMath.pow(r, k); if ((stdMath.abs(x-p)<1.0) && ((0x) ? -r : r; return 1; } function ikthroot(n, k) { // Return the integer k-th root of a number by Newton's method var Arithmetic = Abacus.Arithmetic, I = Arithmetic.I, u, r, k_1; if (Arithmetic.gt(I, k)) return null; // undefined else if (Arithmetic.equ(I, k) || Arithmetic.equ(n, I) || Arithmetic.equ(n, Arithmetic.O)) return n; if (Arithmetic.isDefault() || Arithmetic.lte(n, MAX_DEFAULT)) return Arithmetic.num(stdMath.floor(jskthroot(Arithmetic.val(n), Arithmetic.val(k)))); k_1 = Arithmetic.sub(k, I); u = n; r = Arithmetic.add(n, I); while (Arithmetic.lt(u, r)) { r = u; u = Arithmetic.div(Arithmetic.add(Arithmetic.mul(r, k_1), Arithmetic.div(n, Arithmetic.pow(r, k_1))), k); } return r; } function polykthroot(p, k, limit) { // Return the (possibly truncated) k-th root of a polynomial // https://math.stackexchange.com/questions/324385/algorithm-for-finding-the-square-root-of-a-polynomial // https://planetmath.org/SquareRootOfPolynomial // https://math.stackexchange.com/questions/3550942/algorithm-to-compute-nth-root-radical-sqrtnpx-of-polynomial // similarities with modified Newton's algorithm adapted for polynomials var Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, I = Arithmetic.I, two = Arithmetic.II, PolynomialClass, k_1, r, rk, d, q, deg, nterms = 0; if (k.lt(I)) return null; // undefined else if ((k.equ(I)) || p.equ(O) || p.equ(I)) return p; PolynomialClass = p[CLASS]; if (null == limit) limit = 6; limit = stdMath.abs(+limit); k_1 = k.sub(I); // using tail term .ttm(), correctly computes (taylor) power series approximation if p is not perfect kth power r = new PolynomialClass(p.ttm().rad(k), p.symbol, p.ring); deg = p.maxdeg(true); rk = r.pow(k_1); d = p.sub(rk.mul(r)); while (!d.equ(O)) { q = d.ttm(true).div(rk.mul(k).ttm(true)); if (q.equ(O)) break; // no update anymore /*d = d.sub(q.mul(rk.add(q.pow(k_1))));*/ r = r.add(q); rk = r.pow(k_1); d = p.sub(rk.mul(r)); // compute only up to some terms of power series (truncated power series approximation) // if p is not a perfect kth power and root begins to have powers not belonging to the root of p if (r.maxdeg(true)*k > deg) { nterms++; if ((r.terms.length >= limit) || (nterms >= limit)) break; } } // normalise r to have positive lead coeff // if k is multiple of 2 (since then both r and -r are roots) // and is not a (truncated) power series approximation return (0===nterms) && k.mod(two).equ(O) ? r.abs() : r; } function kthroot(x, k, limit) { // https://en.wikipedia.org/wiki/Nth_root_algorithm // https://en.wikipedia.org/wiki/Shifting_nth_root_algorithm // Return the approximate k-th root of a rational number by Newton's method var Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, I = Arithmetic.I, two = Arithmetic.II, ObjectClass, r, d, k_1, tries = 0, epsilon = Rational.Epsilon(); if (k.equ(O)) return null; if ((is_instance(x, Numeric) && (x.equ(O) || x.equ(I))) || (Arithmetic.isNumber(x) && (Arithmetic.equ(O, x) || Arithmetic.equ(I, x)))) return x; ObjectClass = Arithmetic.isNumber(x) || is_instance(x, Integer) ? Rational : x[CLASS]; x = ObjectClass.cast(x); if (is_class(ObjectClass, Rational) && x.lt(O) && k.mod(two).equ(O)) { // square root of negative real number, transform to complex ObjectClass = Complex; x = ObjectClass.cast(x); } if (k.lt(O)) { x = x.inv(); k = k.neg(); } if (k.equ(I)) return x; if (is_class(ObjectClass, RationalFunc)) { r = new ObjectClass(polykthroot(x.num, k), polykthroot(x.den, k)); } else if (is_class(ObjectClass, Rational)) { r = new ObjectClass(ikthroot(x.num, k.num), ikthroot(x.den, k.num)); } else if (is_class(ObjectClass, Complex)) { if (x.isReal() && (x.real().gte(O) || !k.mod(two).equ(O))) { r = new ObjectClass(Rational(ikthroot(x.real().num, k.num), ikthroot(x.real().den, k.num)), Rational.Zero()); } else { r = new ObjectClass(I, I); // make sure a complex is used, not strictly real or imag } } else { r = ObjectClass.One(); } //if (null == limit) limit = 6; // for up to 6 tries Newton method converges with 64bit precision //limit = stdMath.abs(+limit); k_1 = k.sub(I); if (is_class(ObjectClass, Complex)) { do { d = x.div(r.pow(k_1)).sub(r).div(k); if (d.real().abs().lte(epsilon) && d.imag().abs().lte(epsilon)) break; r = r.add(d); } while (true); } else { do { d = x.div(r.pow(k_1)).sub(r).div(k); if (d.abs().lte(epsilon)) break; r = r.add(d); } while (true); } return r; } /*function quadres(a, n) { // https://en.wikipedia.org/wiki/Quadratic_residue var Arithmetic = Abacus.Arithmetic, N = Arithmetic.num, O = Arithmetic.O, I = Arithmetic.I, two = Arithmetic.II, q, x, z; a = N(a); n = N(n); q = Arithmetic.div(Arithmetic.sub(n, I), two); x = q; //Arithmetic.pow(q, I); if (Arithmetic.equ(x, O)) return I; a = Arithmetic.mod(a, n); z = I; while (!Arithmetic.equ(x, O)) { if (Arithmetic.equ(O, Arithmetic.mod(x, two))) { a = Arithmetic.mod(Arithmetic.mul(a, a), n); x = Arithmetic.div(x, two); } else { x = Arithmetic.sub(x, I); z = Arithmetic.mod(Arithmetic.mul(z, a), n); } } return z; }*/ function jacobi_symbol(m, n, g) { // https://en.wikipedia.org/wiki/Jacobi_symbol var Arithmetic = Abacus.Arithmetic, N = Arithmetic.num, O = Arithmetic.O, J = Arithmetic.J, I = Arithmetic.I, two = Arithmetic.II, j, t, three, four, five, eight; if (Arithmetic.lt(n, O) || Arithmetic.equ(O, Arithmetic.mod(n, two))) return null; //n should be an odd positive integer if (Arithmetic.lt(m, O) || Arithmetic.gt(m, n)) m = Arithmetic.mod(m, n); if (Arithmetic.equ(O, m)) return Arithmetic.equ(I, n) ? I : O; if (Arithmetic.equ(I, n) || Arithmetic.equ(I, m)) return I; if (null == g) g = gcd(m, n); if (!Arithmetic.equ(I, g)) return O; three = N(3); four = N(4); five = N(5); eight = N(8); j = I; if (Arithmetic.lt(m, O)) { m = Arithmetic.mul(J, m); if (Arithmetic.equ(Arithmetic.mod(n, four), three)) j = Arithmetic.mul(J, j); } while (!Arithmetic.equ(O, m)) { while (Arithmetic.gt(m, O) && Arithmetic.equ(O, Arithmetic.mod(m, two))) { m = Arithmetic.div(m, two); t = Arithmetic.mod(n, eight); if (Arithmetic.equ(t, three) || Arithmetic.equ(t, five)) j = Arithmetic.mul(J, j); } t = m; m = n; n = t; if (Arithmetic.equ(three, Arithmetic.mod(m, four)) && Arithmetic.equ(three, Arithmetic.mod(n, four))) j = Arithmetic.mul(J, j); m = Arithmetic.mod(m, n); } if (!Arithmetic.equ(I, n)) j = O; return j; } function legendre_symbol(a, p) { // https://en.wikipedia.org/wiki/Legendre_symbol var Arithmetic = Abacus.Arithmetic, N = Arithmetic.num, I = Arithmetic.I, two = Arithmetic.II; //a = N(a); p = N(p); // built-in powm uses exponention by squaring thus is efficient return powm(a, Arithmetic.div(Arithmetic.sub(p, I), two), p); } function isqrtp(n, p) { // square root modulo prime p // https://en.wikipedia.org/wiki/Quadratic_residue // https://en.wikipedia.org/wiki/Tonelli%E2%80%93Shanks_algorithm var Arithmetic = Abacus.Arithmetic, N = Arithmetic.num, O = Arithmetic.O, I = Arithmetic.I, two, p_1, q, s, z, c, r, r2, t, m, t2, b, i; //n = N(n); p = N(p); if (!Arithmetic.equ(I, legendre_symbol(n, p))) return null; // not a square (mod p) two = Arithmetic.II; p_1 = Arithmetic.sub(p, I); q = p_1; s = 0 while (Arithmetic.equ(O, Arithmetic.mod(q, two))) { q = Arithmetic.div(q, two); s += 1; } if (1 === s) return powm(n, Arithmetic.div(Arithmetic.add(p, I), 4), p); for (z=O; Arithmetic.lt(z, p); z=Arithmetic.add(z, I)) { if (Arithmetic.equ(p_1, legendre_symbol(z, p))) break; } c = powm(z, q, p); r = powm(n, Arithmetic.div(Arithmetic.add(q, I), two), p); t = powm(n, q, p); m = s; t2 = O while (!Arithmetic.equ(O, Arithmetic.mod(Arithmetic.sub(t, I), p))) { t2 = mulm(t, t, p); for (i=1; i i ? '0' : bits.slice(0, i+1)] : z; } function small_primes() { var N = Abacus.Arithmetic.num; if (!small_primes.list) { // a list of the first primes up to a limit (first 2000 primes) small_primes.list = [N(2),N(3),N(5),N(7),N(11),N(13),N(17),N(19),N(23),N(29),N(31),N(37),N(41),N(43),N(47),N(53),N(59),N(61),N(67),N(71),N(73),N(79),N(83),N(89),N(97),N(101),N(103),N(107),N(109),N(113),N(127),N(131),N(137),N(139),N(149),N(151),N(157),N(163),N(167),N(173),N(179),N(181),N(191),N(193),N(197),N(199),N(211),N(223),N(227),N(229),N(233),N(239),N(241),N(251),N(257),N(263),N(269),N(271),N(277),N(281),N(283),N(293),N(307),N(311),N(313),N(317),N(331),N(337),N(347),N(349),N(353),N(359),N(367),N(373),N(379),N(383),N(389),N(397),N(401),N(409),N(419),N(421),N(431),N(433),N(439),N(443),N(449),N(457),N(461),N(463),N(467),N(479),N(487),N(491),N(499),N(503),N(509),N(521),N(523),N(541),N(547),N(557),N(563),N(569),N(571),N(577),N(587),N(593),N(599),N(601),N(607),N(613),N(617),N(619),N(631),N(641),N(643),N(647),N(653),N(659),N(661),N(673),N(677),N(683),N(691),N(701),N(709),N(719),N(727),N(733),N(739),N(743),N(751),N(757),N(761),N(769),N(773),N(787),N(797),N(809),N(811),N(821),N(823),N(827),N(829),N(839),N(853),N(857),N(859),N(863),N(877),N(881),N(883),N(887),N(907),N(911),N(919),N(929),N(937),N(941),N(947),N(953),N(967),N(971),N(977),N(983),N(991),N(997),N(1009),N(1013),N(1019),N(1021),N(1031),N(1033),N(1039),N(1049),N(1051),N(1061),N(1063),N(1069),N(1087),N(1091),N(1093),N(1097),N(1103),N(1109),N(1117),N(1123),N(1129),N(1151),N(1153),N(1163),N(1171),N(1181),N(1187),N(1193),N(1201),N(1213),N(1217),N(1223),N(1229),N(1231),N(1237),N(1249),N(1259),N(1277),N(1279),N(1283),N(1289),N(1291),N(1297),N(1301),N(1303),N(1307),N(1319),N(1321),N(1327),N(1361),N(1367),N(1373),N(1381),N(1399),N(1409),N(1423),N(1427),N(1429),N(1433),N(1439),N(1447),N(1451),N(1453),N(1459),N(1471),N(1481),N(1483),N(1487),N(1489),N(1493),N(1499),N(1511),N(1523),N(1531),N(1543),N(1549),N(1553),N(1559),N(1567),N(1571),N(1579),N(1583),N(1597),N(1601),N(1607),N(1609),N(1613),N(1619),N(1621),N(1627),N(1637),N(1657),N(1663),N(1667),N(1669),N(1693),N(1697),N(1699),N(1709),N(1721),N(1723),N(1733),N(1741),N(1747),N(1753),N(1759),N(1777),N(1783),N(1787),N(1789),N(1801),N(1811),N(1823),N(1831),N(1847),N(1861),N(1867),N(1871),N(1873),N(1877),N(1879),N(1889),N(1901),N(1907),N(1913),N(1931),N(1933),N(1949),N(1951),N(1973),N(1979),N(1987),N(1993),N(1997),N(1999),N(2003),N(2011),N(2017),N(2027),N(2029),N(2039),N(2053),N(2063),N(2069),N(2081),N(2083),N(2087),N(2089),N(2099),N(2111),N(2113),N(2129),N(2131),N(2137),N(2141),N(2143),N(2153),N(2161),N(2179),N(2203),N(2207),N(2213),N(2221),N(2237),N(2239),N(2243),N(2251),N(2267),N(2269),N(2273),N(2281),N(2287),N(2293),N(2297),N(2309),N(2311),N(2333),N(2339),N(2341),N(2347),N(2351),N(2357),N(2371),N(2377),N(2381),N(2383),N(2389),N(2393),N(2399),N(2411),N(2417),N(2423),N(2437),N(2441),N(2447),N(2459),N(2467),N(2473),N(2477),N(2503),N(2521),N(2531),N(2539),N(2543),N(2549),N(2551),N(2557),N(2579),N(2591),N(2593),N(2609),N(2617),N(2621),N(2633),N(2647),N(2657),N(2659),N(2663),N(2671),N(2677),N(2683),N(2687),N(2689),N(2693),N(2699),N(2707),N(2711),N(2713),N(2719),N(2729),N(2731),N(2741),N(2749),N(2753),N(2767),N(2777),N(2789),N(2791),N(2797),N(2801),N(2803),N(2819),N(2833),N(2837),N(2843),N(2851),N(2857),N(2861),N(2879),N(2887),N(2897),N(2903),N(2909),N(2917),N(2927),N(2939),N(2953),N(2957),N(2963),N(2969),N(2971),N(2999),N(3001),N(3011),N(3019),N(3023),N(3037),N(3041),N(3049),N(3061),N(3067),N(3079),N(3083),N(3089),N(3109),N(3119),N(3121),N(3137),N(3163),N(3167),N(3169),N(3181),N(3187),N(3191),N(3203),N(3209),N(3217),N(3221),N(3229),N(3251),N(3253),N(3257),N(3259),N(3271),N(3299),N(3301),N(3307),N(3313),N(3319),N(3323),N(3329),N(3331),N(3343),N(3347),N(3359),N(3361),N(3371),N(3373),N(3389),N(3391),N(3407),N(3413),N(3433),N(3449),N(3457),N(3461),N(3463),N(3467),N(3469),N(3491),N(3499),N(3511),N(3517),N(3527),N(3529),N(3533),N(3539),N(3541),N(3547),N(3557),N(3559),N(3571),N(3581),N(3583),N(3593),N(3607),N(3613),N(3617),N(3623),N(3631),N(3637),N(3643),N(3659),N(3671),N(3673),N(3677),N(3691),N(3697),N(3701),N(3709),N(3719),N(3727),N(3733),N(3739),N(3761),N(3767),N(3769),N(3779),N(3793),N(3797),N(3803),N(3821),N(3823),N(3833),N(3847),N(3851),N(3853),N(3863),N(3877),N(3881),N(3889),N(3907),N(3911),N(3917),N(3919),N(3923),N(3929),N(3931),N(3943),N(3947),N(3967),N(3989),N(4001),N(4003),N(4007),N(4013),N(4019),N(4021),N(4027),N(4049),N(4051),N(4057),N(4073),N(4079),N(4091),N(4093),N(4099),N(4111),N(4127),N(4129),N(4133),N(4139),N(4153),N(4157),N(4159),N(4177),N(4201),N(4211),N(4217),N(4219),N(4229),N(4231),N(4241),N(4243),N(4253),N(4259),N(4261),N(4271),N(4273),N(4283),N(4289),N(4297),N(4327),N(4337),N(4339),N(4349),N(4357),N(4363),N(4373),N(4391),N(4397),N(4409),N(4421),N(4423),N(4441),N(4447),N(4451),N(4457),N(4463),N(4481),N(4483),N(4493),N(4507),N(4513),N(4517),N(4519),N(4523),N(4547),N(4549),N(4561),N(4567),N(4583),N(4591),N(4597),N(4603),N(4621),N(4637),N(4639),N(4643),N(4649),N(4651),N(4657),N(4663),N(4673),N(4679),N(4691),N(4703),N(4721),N(4723),N(4729),N(4733),N(4751),N(4759),N(4783),N(4787),N(4789),N(4793),N(4799),N(4801),N(4813),N(4817),N(4831),N(4861),N(4871),N(4877),N(4889),N(4903),N(4909),N(4919),N(4931),N(4933),N(4937),N(4943),N(4951),N(4957),N(4967),N(4969),N(4973),N(4987),N(4993),N(4999),N(5003),N(5009),N(5011),N(5021),N(5023),N(5039),N(5051),N(5059),N(5077),N(5081),N(5087),N(5099),N(5101),N(5107),N(5113),N(5119),N(5147),N(5153),N(5167),N(5171),N(5179),N(5189),N(5197),N(5209),N(5227),N(5231),N(5233),N(5237),N(5261),N(5273),N(5279),N(5281),N(5297),N(5303),N(5309),N(5323),N(5333),N(5347),N(5351),N(5381),N(5387),N(5393),N(5399),N(5407),N(5413),N(5417),N(5419),N(5431),N(5437),N(5441),N(5443),N(5449),N(5471),N(5477),N(5479),N(5483),N(5501),N(5503),N(5507),N(5519),N(5521),N(5527),N(5531),N(5557),N(5563),N(5569),N(5573),N(5581),N(5591),N(5623),N(5639),N(5641),N(5647),N(5651),N(5653),N(5657),N(5659),N(5669),N(5683),N(5689),N(5693),N(5701),N(5711),N(5717),N(5737),N(5741),N(5743),N(5749),N(5779),N(5783),N(5791),N(5801),N(5807),N(5813),N(5821),N(5827),N(5839),N(5843),N(5849),N(5851),N(5857),N(5861),N(5867),N(5869),N(5879),N(5881),N(5897),N(5903),N(5923),N(5927),N(5939),N(5953),N(5981),N(5987),N(6007),N(6011),N(6029),N(6037),N(6043),N(6047),N(6053),N(6067),N(6073),N(6079),N(6089),N(6091),N(6101),N(6113),N(6121),N(6131),N(6133),N(6143),N(6151),N(6163),N(6173),N(6197),N(6199),N(6203),N(6211),N(6217),N(6221),N(6229),N(6247),N(6257),N(6263),N(6269),N(6271),N(6277),N(6287),N(6299),N(6301),N(6311),N(6317),N(6323),N(6329),N(6337),N(6343),N(6353),N(6359),N(6361),N(6367),N(6373),N(6379),N(6389),N(6397),N(6421),N(6427),N(6449),N(6451),N(6469),N(6473),N(6481),N(6491),N(6521),N(6529),N(6547),N(6551),N(6553),N(6563),N(6569),N(6571),N(6577),N(6581),N(6599),N(6607),N(6619),N(6637),N(6653),N(6659),N(6661),N(6673),N(6679),N(6689),N(6691),N(6701),N(6703),N(6709),N(6719),N(6733),N(6737),N(6761),N(6763),N(6779),N(6781),N(6791),N(6793),N(6803),N(6823),N(6827),N(6829),N(6833),N(6841),N(6857),N(6863),N(6869),N(6871),N(6883),N(6899),N(6907),N(6911),N(6917),N(6947),N(6949),N(6959),N(6961),N(6967),N(6971),N(6977),N(6983),N(6991),N(6997),N(7001),N(7013),N(7019),N(7027),N(7039),N(7043),N(7057),N(7069),N(7079),N(7103),N(7109),N(7121),N(7127),N(7129),N(7151),N(7159),N(7177),N(7187),N(7193),N(7207),N(7211),N(7213),N(7219),N(7229),N(7237),N(7243),N(7247),N(7253),N(7283),N(7297),N(7307),N(7309),N(7321),N(7331),N(7333),N(7349),N(7351),N(7369),N(7393),N(7411),N(7417),N(7433),N(7451),N(7457),N(7459),N(7477),N(7481),N(7487),N(7489),N(7499),N(7507),N(7517),N(7523),N(7529),N(7537),N(7541),N(7547),N(7549),N(7559),N(7561),N(7573),N(7577),N(7583),N(7589),N(7591),N(7603),N(7607),N(7621),N(7639),N(7643),N(7649),N(7669),N(7673),N(7681),N(7687),N(7691),N(7699),N(7703),N(7717),N(7723),N(7727),N(7741),N(7753),N(7757),N(7759),N(7789),N(7793),N(7817),N(7823),N(7829),N(7841),N(7853),N(7867),N(7873),N(7877),N(7879),N(7883),N(7901),N(7907),N(7919),N(7927),N(7933),N(7937),N(7949),N(7951),N(7963),N(7993),N(8009),N(8011),N(8017),N(8039),N(8053),N(8059),N(8069),N(8081),N(8087),N(8089),N(8093),N(8101),N(8111),N(8117),N(8123),N(8147),N(8161),N(8167),N(8171),N(8179),N(8191),N(8209),N(8219),N(8221),N(8231),N(8233),N(8237),N(8243),N(8263),N(8269),N(8273),N(8287),N(8291),N(8293),N(8297),N(8311),N(8317),N(8329),N(8353),N(8363),N(8369),N(8377),N(8387),N(8389),N(8419),N(8423),N(8429),N(8431),N(8443),N(8447),N(8461),N(8467),N(8501),N(8513),N(8521),N(8527),N(8537),N(8539),N(8543),N(8563),N(8573),N(8581),N(8597),N(8599),N(8609),N(8623),N(8627),N(8629),N(8641),N(8647),N(8663),N(8669),N(8677),N(8681),N(8689),N(8693),N(8699),N(8707),N(8713),N(8719),N(8731),N(8737),N(8741),N(8747),N(8753),N(8761),N(8779),N(8783),N(8803),N(8807),N(8819),N(8821),N(8831),N(8837),N(8839),N(8849),N(8861),N(8863),N(8867),N(8887),N(8893),N(8923),N(8929),N(8933),N(8941),N(8951),N(8963),N(8969),N(8971),N(8999),N(9001),N(9007),N(9011),N(9013),N(9029),N(9041),N(9043),N(9049),N(9059),N(9067),N(9091),N(9103),N(9109),N(9127),N(9133),N(9137),N(9151),N(9157),N(9161),N(9173),N(9181),N(9187),N(9199),N(9203),N(9209),N(9221),N(9227),N(9239),N(9241),N(9257),N(9277),N(9281),N(9283),N(9293),N(9311),N(9319),N(9323),N(9337),N(9341),N(9343),N(9349),N(9371),N(9377),N(9391),N(9397),N(9403),N(9413),N(9419),N(9421),N(9431),N(9433),N(9437),N(9439),N(9461),N(9463),N(9467),N(9473),N(9479),N(9491),N(9497),N(9511),N(9521),N(9533),N(9539),N(9547),N(9551),N(9587),N(9601),N(9613),N(9619),N(9623),N(9629),N(9631),N(9643),N(9649),N(9661),N(9677),N(9679),N(9689),N(9697),N(9719),N(9721),N(9733),N(9739),N(9743),N(9749),N(9767),N(9769),N(9781),N(9787),N(9791),N(9803),N(9811),N(9817),N(9829),N(9833),N(9839),N(9851),N(9857),N(9859),N(9871),N(9883),N(9887),N(9901),N(9907),N(9923),N(9929),N(9931),N(9941),N(9949),N(9967),N(9973),N(10007),N(10009),N(10037),N(10039),N(10061),N(10067),N(10069),N(10079),N(10091),N(10093),N(10099),N(10103),N(10111),N(10133),N(10139),N(10141),N(10151),N(10159),N(10163),N(10169),N(10177),N(10181),N(10193),N(10211),N(10223),N(10243),N(10247),N(10253),N(10259),N(10267),N(10271),N(10273),N(10289),N(10301),N(10303),N(10313),N(10321),N(10331),N(10333),N(10337),N(10343),N(10357),N(10369),N(10391),N(10399),N(10427),N(10429),N(10433),N(10453),N(10457),N(10459),N(10463),N(10477),N(10487),N(10499),N(10501),N(10513),N(10529),N(10531),N(10559),N(10567),N(10589),N(10597),N(10601),N(10607),N(10613),N(10627),N(10631),N(10639),N(10651),N(10657),N(10663),N(10667),N(10687),N(10691),N(10709),N(10711),N(10723),N(10729),N(10733),N(10739),N(10753),N(10771),N(10781),N(10789),N(10799),N(10831),N(10837),N(10847),N(10853),N(10859),N(10861),N(10867),N(10883),N(10889),N(10891),N(10903),N(10909),N(10937),N(10939),N(10949),N(10957),N(10973),N(10979),N(10987),N(10993),N(11003),N(11027),N(11047),N(11057),N(11059),N(11069),N(11071),N(11083),N(11087),N(11093),N(11113),N(11117),N(11119),N(11131),N(11149),N(11159),N(11161),N(11171),N(11173),N(11177),N(11197),N(11213),N(11239),N(11243),N(11251),N(11257),N(11261),N(11273),N(11279),N(11287),N(11299),N(11311),N(11317),N(11321),N(11329),N(11351),N(11353),N(11369),N(11383),N(11393),N(11399),N(11411),N(11423),N(11437),N(11443),N(11447),N(11467),N(11471),N(11483),N(11489),N(11491),N(11497),N(11503),N(11519),N(11527),N(11549),N(11551),N(11579),N(11587),N(11593),N(11597),N(11617),N(11621),N(11633),N(11657),N(11677),N(11681),N(11689),N(11699),N(11701),N(11717),N(11719),N(11731),N(11743),N(11777),N(11779),N(11783),N(11789),N(11801),N(11807),N(11813),N(11821),N(11827),N(11831),N(11833),N(11839),N(11863),N(11867),N(11887),N(11897),N(11903),N(11909),N(11923),N(11927),N(11933),N(11939),N(11941),N(11953),N(11959),N(11969),N(11971),N(11981),N(11987),N(12007),N(12011),N(12037),N(12041),N(12043),N(12049),N(12071),N(12073),N(12097),N(12101),N(12107),N(12109),N(12113),N(12119),N(12143),N(12149),N(12157),N(12161),N(12163),N(12197),N(12203),N(12211),N(12227),N(12239),N(12241),N(12251),N(12253),N(12263),N(12269),N(12277),N(12281),N(12289),N(12301),N(12323),N(12329),N(12343),N(12347),N(12373),N(12377),N(12379),N(12391),N(12401),N(12409),N(12413),N(12421),N(12433),N(12437),N(12451),N(12457),N(12473),N(12479),N(12487),N(12491),N(12497),N(12503),N(12511),N(12517),N(12527),N(12539),N(12541),N(12547),N(12553),N(12569),N(12577),N(12583),N(12589),N(12601),N(12611),N(12613),N(12619),N(12637),N(12641),N(12647),N(12653),N(12659),N(12671),N(12689),N(12697),N(12703),N(12713),N(12721),N(12739),N(12743),N(12757),N(12763),N(12781),N(12791),N(12799),N(12809),N(12821),N(12823),N(12829),N(12841),N(12853),N(12889),N(12893),N(12899),N(12907),N(12911),N(12917),N(12919),N(12923),N(12941),N(12953),N(12959),N(12967),N(12973),N(12979),N(12983),N(13001),N(13003),N(13007),N(13009),N(13033),N(13037),N(13043),N(13049),N(13063),N(13093),N(13099),N(13103),N(13109),N(13121),N(13127),N(13147),N(13151),N(13159),N(13163),N(13171),N(13177),N(13183),N(13187),N(13217),N(13219),N(13229),N(13241),N(13249),N(13259),N(13267),N(13291),N(13297),N(13309),N(13313),N(13327),N(13331),N(13337),N(13339),N(13367),N(13381),N(13397),N(13399),N(13411),N(13417),N(13421),N(13441),N(13451),N(13457),N(13463),N(13469),N(13477),N(13487),N(13499),N(13513),N(13523),N(13537),N(13553),N(13567),N(13577),N(13591),N(13597),N(13613),N(13619),N(13627),N(13633),N(13649),N(13669),N(13679),N(13681),N(13687),N(13691),N(13693),N(13697),N(13709),N(13711),N(13721),N(13723),N(13729),N(13751),N(13757),N(13759),N(13763),N(13781),N(13789),N(13799),N(13807),N(13829),N(13831),N(13841),N(13859),N(13873),N(13877),N(13879),N(13883),N(13901),N(13903),N(13907),N(13913),N(13921),N(13931),N(13933),N(13963),N(13967),N(13997),N(13999),N(14009),N(14011),N(14029),N(14033),N(14051),N(14057),N(14071),N(14081),N(14083),N(14087),N(14107),N(14143),N(14149),N(14153),N(14159),N(14173),N(14177),N(14197),N(14207),N(14221),N(14243),N(14249),N(14251),N(14281),N(14293),N(14303),N(14321),N(14323),N(14327),N(14341),N(14347),N(14369),N(14387),N(14389),N(14401),N(14407),N(14411),N(14419),N(14423),N(14431),N(14437),N(14447),N(14449),N(14461),N(14479),N(14489),N(14503),N(14519),N(14533),N(14537),N(14543),N(14549),N(14551),N(14557),N(14561),N(14563),N(14591),N(14593),N(14621),N(14627),N(14629),N(14633),N(14639),N(14653),N(14657),N(14669),N(14683),N(14699),N(14713),N(14717),N(14723),N(14731),N(14737),N(14741),N(14747),N(14753),N(14759),N(14767),N(14771),N(14779),N(14783),N(14797),N(14813),N(14821),N(14827),N(14831),N(14843),N(14851),N(14867),N(14869),N(14879),N(14887),N(14891),N(14897),N(14923),N(14929),N(14939),N(14947),N(14951),N(14957),N(14969),N(14983),N(15013),N(15017),N(15031),N(15053),N(15061),N(15073),N(15077),N(15083),N(15091),N(15101),N(15107),N(15121),N(15131),N(15137),N(15139),N(15149),N(15161),N(15173),N(15187),N(15193),N(15199),N(15217),N(15227),N(15233),N(15241),N(15259),N(15263),N(15269),N(15271),N(15277),N(15287),N(15289),N(15299),N(15307),N(15313),N(15319),N(15329),N(15331),N(15349),N(15359),N(15361),N(15373),N(15377),N(15383),N(15391),N(15401),N(15413),N(15427),N(15439),N(15443),N(15451),N(15461),N(15467),N(15473),N(15493),N(15497),N(15511),N(15527),N(15541),N(15551),N(15559),N(15569),N(15581),N(15583),N(15601),N(15607),N(15619),N(15629),N(15641),N(15643),N(15647),N(15649),N(15661),N(15667),N(15671),N(15679),N(15683),N(15727),N(15731),N(15733),N(15737),N(15739),N(15749),N(15761),N(15767),N(15773),N(15787),N(15791),N(15797),N(15803),N(15809),N(15817),N(15823),N(15859),N(15877),N(15881),N(15887),N(15889),N(15901),N(15907),N(15913),N(15919),N(15923),N(15937),N(15959),N(15971),N(15973),N(15991),N(16001),N(16007),N(16033),N(16057),N(16061),N(16063),N(16067),N(16069),N(16073),N(16087),N(16091),N(16097),N(16103),N(16111),N(16127),N(16139),N(16141),N(16183),N(16187),N(16189),N(16193),N(16217),N(16223),N(16229),N(16231),N(16249),N(16253),N(16267),N(16273),N(16301),N(16319),N(16333),N(16339),N(16349),N(16361),N(16363),N(16369),N(16381),N(16411),N(16417),N(16421),N(16427),N(16433),N(16447),N(16451),N(16453),N(16477),N(16481),N(16487),N(16493),N(16519),N(16529),N(16547),N(16553),N(16561),N(16567),N(16573),N(16603),N(16607),N(16619),N(16631),N(16633),N(16649),N(16651),N(16657),N(16661),N(16673),N(16691),N(16693),N(16699),N(16703),N(16729),N(16741),N(16747),N(16759),N(16763),N(16787),N(16811),N(16823),N(16829),N(16831),N(16843),N(16871),N(16879),N(16883),N(16889),N(16901),N(16903),N(16921),N(16927),N(16931),N(16937),N(16943),N(16963),N(16979),N(16981),N(16987),N(16993),N(17011),N(17021),N(17027),N(17029),N(17033),N(17041),N(17047),N(17053),N(17077),N(17093),N(17099),N(17107),N(17117),N(17123),N(17137),N(17159),N(17167),N(17183),N(17189),N(17191),N(17203),N(17207),N(17209),N(17231),N(17239),N(17257),N(17291),N(17293),N(17299),N(17317),N(17321),N(17327),N(17333),N(17341),N(17351),N(17359),N(17377),N(17383),N(17387),N(17389)]; } return small_primes.list; } /*function fermat_test(n, k) { // https://en.wikipedia.org/wiki/Fermat_primality_test // https://en.wikipedia.org/wiki/Fermat_pseudoprime var Arithmetic = Abacus.Arithmetic, I = Arithmetic.I, two = Arithmetic.II, n_1, n_2, i, kl, a; if (Arithmetic.lt(n, two)) return false; else if (Arithmetic.equ(n, two) || Arithmetic.equ(n, 3)) return true; n_1 = Arithmetic.sub(n, I); if (null == k) k = 3; if (is_array(k)) { for (i=0,kl=k.length; i= 2 //else if (Arithmetic.lt(k, O)) return null; //k must be >= 0 D = Arithmetic.sub(Arithmetic.mul(P, P), Arithmetic.mul(Q, 4)); if (Arithmetic.equ(O, D)) return null; //D must not be zero bits = bits || Arithmetic.digits(k, 2); if ('0'===bits /*|| Arithmetic.equ(O, k)*/) return [O, two, Q]; U = I; V = P; Qk = Q; b = bits.length; if (Arithmetic.equ(I, Q)) { // Optimization for extra strong tests. for (bit=1; bit> (b - 1)) & 1*/) { U0 = U; V0 = V; U = Arithmetic.add(Arithmetic.mul(U0, P), V0); V = Arithmetic.add(Arithmetic.mul(V0, P), Arithmetic.mul(U0, D)); if (Arithmetic.equ(I, Arithmetic.mod(U, two))) U = Arithmetic.add(U, n); if (Arithmetic.equ(I, Arithmetic.mod(V, two))) V = Arithmetic.add(V, n); U = Arithmetic.div(U, two); V = Arithmetic.div(V, two); } } } else if (Arithmetic.equ(I, P) && Arithmetic.equ(J, Q)) { // Small optimization for 50% of Selfridge parameters. for (bit=1; bit> (b - 1)) & 1*/) { U0 = U; V0 = V; U = Arithmetic.add(U0, V0); V = Arithmetic.add(V0, Arithmetic.mul(U0, D)); if (Arithmetic.equ(I, Arithmetic.mod(U, two))) U = Arithmetic.add(U, n); if (Arithmetic.equ(I, Arithmetic.mod(V, two))) V = Arithmetic.add(V, n); U = Arithmetic.div(U, two); V = Arithmetic.div(V, two); Qk = J; } } } else { // The general case with any P and Q. for (bit=1; bit> (b - 1)) & 1*/) { U0 = U; V0 = V; U = Arithmetic.add(Arithmetic.mul(U0, P), V0); V = Arithmetic.add(Arithmetic.mul(V0, P), Arithmetic.mul(U0, D)); if (Arithmetic.equ(I, Arithmetic.mod(U, two))) U = Arithmetic.add(U, n); if (Arithmetic.equ(I, Arithmetic.mod(V, two))) V = Arithmetic.add(V, n); U = Arithmetic.div(U, two); V = Arithmetic.div(V, two); Qk = Arithmetic.mul(Qk, Q); } Qk = Arithmetic.mod(Qk, n); } } return [Arithmetic.mod(U, n), Arithmetic.mod(V, n), Qk]; } /*function lucas_selfridge_params(n) { // https://en.wikipedia.org/wiki/Lucas_pseudoprime var Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, J = Arithmetic.J, I = Arithmetic.I, two = Arithmetic.II, D, g; D = Arithmetic.num(5); for (;;) { g = gcd(D, n); if (Arithmetic.gt(g, I) && !Arithmetic.equ(g, n)) return [O, O, O]; if (Arithmetic.equ(J, jacobi_symbol(D, n, g))) break; D = Arithmetic.gt(D, O) ? Arithmetic.sub(Arithmetic.mul(J, D), two) : Arithmetic.add(Arithmetic.mul(J, D), two); } return [D, I, Arithmetic.div(Arithmetic.sub(I, D), 4)]; }*/ function lucas_extrastrong_params(n) { // https://en.wikipedia.org/wiki/Lucas_pseudoprime var Arithmetic = Abacus.Arithmetic, N = Arithmetic.num, O = Arithmetic.O, J = Arithmetic.J, I = Arithmetic.I, two = Arithmetic.II, P, Q, D, g, four = N(4); P = N(3); Q = I; D = N(5); for (;;) { g = gcd(D, n); if (Arithmetic.gt(g, I) && !Arithmetic.equ(g, n)) return [O, O, O]; if (Arithmetic.equ(J, jacobi_symbol(D, n, g))) break; P = Arithmetic.add(P, I); D = Arithmetic.sub(Arithmetic.mul(P, P), four); } return [D, P, Q]; } /*function lucas_test(n) { // https://en.wikipedia.org/wiki/Lucas_primality_test // https://en.wikipedia.org/wiki/Lucas_pseudoprime // http://mpqs.free.fr/LucasPseudoprimes.pdf var Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, I = Arithmetic.I, J = Arithmetic.J, two = Arithmetic.II, sqrt, PQ, UV; //if (Arithmetic.equ(n, two)) return true; //if (Arithmetic.lt(n, two) || Arithmetic.equ(O, Arithmetic.mod(n, two))) return false; // Check that the number isn't a square number, as this will throw out // calculating the correct value of D later on (and means we have a composite number) sqrt = isqrt(n); //ikthroot(n, two); if (Arithmetic.equ(n, Arithmetic.mul(sqrt, sqrt))) return false; PQ = lucas_selfridge_params(n); if (Arithmetic.equ(O, PQ[0])) return false; UV = lucas_sequence(n, PQ[1], PQ[2], Arithmetic.add(n, I)); return Arithmetic.equ(O, U[0]); } function strong_lucas_test(n) { // https://en.wikipedia.org/wiki/Lucas_primality_test // https://en.wikipedia.org/wiki/Lucas_pseudoprime // http://mpqs.free.fr/LucasPseudoprimes.pdf var Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, I = Arithmetic.I, J = Arithmetic.J, two = Arithmetic.II, sqrt, PQ, UV, U, V, Qk, s, k, r, bits_k, n_1; //if (Arithmetic.equ(n, two)) return true; //if (Arithmetic.lt(n, two) || Arithmetic.equ(O, Arithmetic.mod(n, two))) return false; // Check that the number isn't a square number, as this will throw out // calculating the correct value of D later on (and means we have a composite number) sqrt = isqrt(n); //ikthroot(n, two); if (Arithmetic.equ(n, Arithmetic.mul(sqrt, sqrt))) return false; PQ = lucas_selfridge_params(n); if (Arithmetic.equ(O, PQ[0])) return false; // remove powers of 2 from n+1 (= k * 2**s) n_1 = Arithmetic.add(n, I); s = trailing_zeroes(n_1, null, true); bits_k = s[1]; s = s[0]; k = O; //Arithmetic.shr(n_1, s); UV = lucas_sequence(n, PQ[1], PQ[2], k, bits_k); U = UV[0]; V = UV[1]; Qk = UV[2]; if (Arithmetic.equ(O, U) || Arithmetic.equ(O, V)) return true; for (r=1; r 1000 digits return baillie_psw_test(n, 7); } } function next_prime(n, dir) { var Arithmetic = Abacus.Arithmetic, N = Arithmetic.num, O = Arithmetic.O, I = Arithmetic.I, two = Arithmetic.II, x; //n = Arithmetic.abs(/*N(*/n/*)*/); dir = -1 === dir ? -1 : 1; if (0 > dir) { // previous prime if (Arithmetic.lte(n, two)) return null; // no previous prime else if (Arithmetic.equ(n, 3)) return two; // first prime for (x=Arithmetic.sub(n, Arithmetic.equ(O, Arithmetic.mod(n, two)) ? I : two);;x=Arithmetic.sub(x,two)) if (is_probable_prime(x) && is_prime(x)) return x; } else { // next prime if (Arithmetic.lt(n, two)) return two; // first prime for (x=Arithmetic.add(n, Arithmetic.equ(O, Arithmetic.mod(n, two)) ? I : two);;x=Arithmetic.add(x,two)) if (is_probable_prime(x) && is_prime(x)) return x; } } function pollard_rho(n, s, a, retries, max_steps, F) { // find a non-trivial factor of n using the Pollard-Rho heuristic // http://en.wikipedia.org/wiki/Pollard%27s_rho_algorithm // https://en.wikipedia.org/wiki/Pohlig%E2%80%93Hellman_algorithm // https://en.wikipedia.org/wiki/Pollard%27s_kangaroo_algorithm var Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, I = Arithmetic.I, two = Arithmetic.II, V, U, i, j, g, n_1, n_3; if (Arithmetic.lte(n, 5)) return Arithmetic.equ(n, 4) ? two : n; // 0,1,2,3,4(=2*2),5 if (null == s) s = two; if (null == a) a = I; if (null == retries) retries = 5; n_1 = Arithmetic.sub(n, I); n_3 = Arithmetic.sub(n, 3); retries = +(retries || 0); max_steps = max_steps || null; F = F || null; V = s; for (i=0; i<=retries; i++) { U = V; j = 0; if (!is_callable(F)) F = function(x) { return Arithmetic.mod(Arithmetic.add(Arithmetic.mod(Arithmetic.mul(x, x), n), a), n); }; for (;;) { if ((null!=max_steps) && (j>max_steps)) break; j += 1; U = F(U); V = F(F(V)); // V is 2x further along than U g = gcd(Arithmetic.sub(U, V), n); if (Arithmetic.equ(I, g)) continue; if (Arithmetic.equ(n, g)) break; return g; } V = Arithmetic.rnd(O, n_1); a = Arithmetic.rnd(I, n_3) // for x^2 + a, a%n should not be 0 or -2 F = null; } return null; } function pollard_pm1(n, B, a, retries) { var Arithmetic = Abacus.Arithmetic, N = Arithmetic.num, O = Arithmetic.O, I = Arithmetic.I, two = Arithmetic.II, i, aM, p, e, g, n_2, B_1, ip, primes = small_primes(), pl = primes.length; if (null == retries) retries = 0; if (null == a) a = two; if (null == B) B = N(10); retries = +retries; //a = N(a); B = N(B); if (Arithmetic.lt(n, 4) || Arithmetic.lt(B, 3)) return null; n_2 = Arithmetic.sub(n, two); //B_1 = Arithmetic.add(B, I); // computing a**lcm(1,2,3,..B) % n for B > 2 // it looks weird, but it's right: primes run [2, B] // and the answer's not right until the loop is done. for (i=0; i<=retries; i++) { aM = a; for (ip=0; ip= l) { p = Arithmetic.add(p, two); p2 = Arithmetic.mul(p, p); while (Arithmetic.lte(p2, n) && (null==maxlimit || Arithmetic.lte(p2, maxlimit))) { e = O; while (Arithmetic.equ(O, Arithmetic.mod(n, p))) { e = Arithmetic.add(I, e); n = Arithmetic.div(n, p); } if (Arithmetic.lt(O, e)) { // add last f = new Node([p, e]); f.l = f1; if (f1) f1.r = f; f1 = f; L++; if (!factors) factors = f1; } p = Arithmetic.add(p, two); p2 = Arithmetic.mul(p, p); } } if ((null==maxlimit) && Arithmetic.gt(n, I)) { // add last f = new Node([n, I]); f.l = f1; if (f1) f1.r = f; f1 = f; L++; if (!factors) factors = f1; } // traverse list of factors and return array fac = array(L, function(){ var f = factors, factor = f.v; factors = factors.r; f.dispose(); // dispose if (factors) factors.l = null; return factor; }); return null == maxlimit ? fac : [fac, n]; // return factorization up to limit + remainder } function siqs_fac(n) { // https://en.wikipedia.org/wiki/Quadratic_sieve // TODO return [[n, Abacus.Arithmetic.I]]; } function merge_factors(f1, f2) { var Arithmetic = Abacus.Arithmetic, i1 = 0, i2 = 0, l1 = f1.length, l2 = f2.length, l = 0, f12; f12 = new Array(l1+l2); while (i1 < l1 && i2 < l2) { if (Arithmetic.equ(f1[i1][0], f2[i2][0])) { if (l && Arithmetic.equ(f12[l-1][0], f1[i1][0])) { f12[l-1][1] = Arithmetic.add(f12[l-1][1], Arithmetic.add(f1[i1][1], f2[i2][1])); } else { f12[l++] = [f1[i1][0], Arithmetic.add(f1[i1][1], f2[i2][1])]; } i1++; i2++; } else if (Arithmetic.lt(f1[i1][0], f2[i2][0])) { if (l && Arithmetic.equ(f12[l-1][0], f1[i1][0])) { f12[l-1][1] = Arithmetic.add(f12[l-1][1], f1[i1][1]); } else { f12[l++] = f1[i1]; } i1++; } else //if (Arithmetic.gt(f1[i1][0], f2[i2][0])) { if (l && Arithmetic.equ(f12[l-1][0], f2[i2][0])) { f12[l-1][1] = Arithmetic.add(f12[l-1][1], f2[i2][1]); } else { f12[l++] = f2[i2]; } i2++; } } while (i1 < l1) { if (l && Arithmetic.equ(f12[l-1][0], f1[i1][0])) { f12[l-1][1] = Arithmetic.add(f12[l-1][1], f1[i1][1]); } else { f12[l++] = f1[i1]; } i1++; } while (i2 < l2) { if (l && Arithmetic.equ(f12[l-1][0], f2[i2][0])) { f12[l-1][1] = Arithmetic.add(f12[l-1][1], f2[i2][1]); } else { f12[l++] = f2[i2]; } i2++; } // truncate if needed if (f12.length > l) f12.length = l; return f12; } function factorize(n) { // https://en.wikipedia.org/wiki/Integer_factorization var Arithmetic = Abacus.Arithmetic, INT = null, ndigits, f, factors; if (is_instance(n, Integer)) { INT = n[CLASS]; n = n.num; } ndigits = Arithmetic.digits(n).length; // try to use fastest algorithm based on size of number (number of digits) if (ndigits <= 20) { // trial division for small numbers factors = trial_div_fac(n); } else //if (ndigits <= 1000) { // recursive (heuristic) factorization for medium-to-large numbers f = pollard_rho(n, Arithmetic.II, Arithmetic.I, 5, 100, null); // try another heuristic as well if (null == f) f = pollard_pm1(n, Arithmetic.num(10), Arithmetic.II, 5); if (null == f) factors = [[n, Arithmetic.I]]; else factors = merge_factors(factorize(f), factorize(Arithmetic.div(n, f))); } /*else { // self-initialising quadratic sieve for (very) large numbers TODO factors = siqs_fac(n); }*/ return INT ? factors.map(function(f){return [new INT(f[0]), new INT(f[1])];}) : factors; } function dec2frac(dec, simplify) { // compute fraction (num/denom) for given decimal number (can include repeating decimals through special notation) // eg -123.23[456] , last 456 digits are repeating infinitely var Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, I = Arithmetic.I, i, n, d, m, g, k, e, ten, fraction, N = Arithmetic.num, is_neg = false, is_zero, non_repeating = null, repeating = null; dec = trim(String(dec)); // convert to string if not already m = dec.match(dec_pattern); if (!m) return null; // not valid decimal if (m[1]) is_neg = true; // negative number, keep track i = N(m[2]); // integer part fraction = [O, I]; ten = N(10); if (!m[3] || (!m[4] && !m[5])) { fraction[0] = is_neg ? Arithmetic.neg(i) : i; if (m[6]) { e = N(m[6].slice(1)); if (Arithmetic.lt(e, O)) fraction[1] = Arithmetic.pow(ten, Arithmetic.neg(e)); else fraction[0] = Arithmetic.mul(fraction[0], Arithmetic.pow(ten, e)); } return fraction; // just integer, no decimal part } if (m[4]) { non_repeating = m[4]; } if (m[5]) { repeating = m[5].slice(1,-1); // remove surrounding brackets is_zero = true; for (k=repeating.length-1; k>=0; k--) { if (repeating.charAt(k) !== '0') { is_zero = false; break; } } if (is_zero) repeating = null; // repeating zeroes are trivial } if (!repeating) { // no repeating decimals // remove unnecessary trailing zeroes while (non_repeating && (non_repeating.slice(-1)==='0')) non_repeating = non_repeating.slice(0, -1); if (!non_repeating || !non_repeating.length) { d = I; n = i; // only integer part } else { d = Arithmetic.pow(ten, non_repeating.length); n = Arithmetic.add(Arithmetic.mul(d, i), N(non_repeating)); } if (m[6]) { e = N(m[6].slice(1)); if (Arithmetic.lt(e, O)) d = Arithmetic.mul(d, Arithmetic.pow(ten, Arithmetic.neg(e))); else n = Arithmetic.mul(n, Arithmetic.pow(ten, e)); } } else { // with repeating decimals if (non_repeating) { // remove common repeating digits from non_repeating digits, in case they are included while ((non_repeating.length>=repeating.length) && (non_repeating.slice(-repeating.length)===repeating)) non_repeating = non_repeating.slice(0, -repeating.length); if (!non_repeating.length) non_repeating = null; } d = Arithmetic.sub(Arithmetic.pow(ten, (non_repeating ? non_repeating.length : 0)+repeating.length), non_repeating ? Arithmetic.pow(ten, non_repeating.length) : I); n = Arithmetic.add(Arithmetic.mul(d, i), Arithmetic.sub(N((non_repeating ? non_repeating : '')+repeating), non_repeating ? N(non_repeating) : O)); } if (false !== simplify) { // remove common factors, simplify g = gcd(n, d); n = Arithmetic.div(n, g); d = Arithmetic.div(d, g); } fraction[0] = is_neg ? Arithmetic.neg(n) : n; fraction[1] = d; return fraction; } function default_eq(a, b) { // default equality between a and b return a===b; } function floyd_cycle_detection(f, x0, eq) { // https://en.wikipedia.org/wiki/Cycle_detection#Floyd's_Tortoise_and_Hare // floyd tortoise-hare algorithm for cycle detection var tortoise, hare, mu, lam; eq = eq || default_eq; tortoise = f(x0); hare = f(tortoise); while (!eq(tortoise, hare)) { tortoise = f(tortoise); hare = f(f(hare)); } mu = 0; tortoise = x0; while (!eq(tortoise, hare)) { tortoise = f(tortoise); hare = f(hare); mu++; } lam = 1; hare = f(tortoise); while (!eq(tortoise, hare)) { hare = f(hare); lam++; } return [lam/*period*/, mu/*first_repeat*/]; } function frac2dec(n, d) { // fraction to decimal, with optional repeating digits var Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, q, r, t, decimal, period, i, c, ten, dot, whole, repeating, non_repeating, is_neg = false, is_zero; if (Arithmetic.equ(O, d)) return null; // not valid fraction is_neg = (Arithmetic.lt(O, n) && Arithmetic.gt(O, d)) || (Arithmetic.lt(O, d) && Arithmetic.gt(O, n)); // keep track if negative number n = Arithmetic.abs(n); d = Arithmetic.abs(d); q = Arithmetic.div(n, d); r = Arithmetic.mod(n, d); whole = (is_neg ? '-' : '') + String(q); decimal = []; ten = Arithmetic.num(10); period = floyd_cycle_detection( function(r) { return Arithmetic.mod(Arithmetic.mul(ten, r), d); }, r, function(a, b) { return Arithmetic.equ(a, b); } ); for (i=0,c=period[0]+period[1]; i=0; i--) { if (repeating.charAt(i) !== '0') { is_zero = false; break; } } if (is_zero) repeating = ''; // repeating zeroes are trivial else repeating = '['+repeating+']'; } non_repeating = decimal.slice(0, period[1]).join(''); if (non_repeating.length) { is_zero = true; for (i=non_repeating.length-1; i>=0; i--) { if (non_repeating.charAt(i) !== '0') { is_zero = false; break; } } if (is_zero && !repeating.length) non_repeating = ''; // zeroes are trivial } dot = non_repeating.length || repeating.length ? '.' : ''; return whole + dot + non_repeating + repeating; } function gcd(/* args */) { // https://en.wikipedia.org/wiki/Euclidean_algorithm // https://en.wikipedia.org/wiki/Greatest_common_divisor // supports Exact Big Integer Arithmetic if plugged in // note: returns always positive gcd (even of negative numbers) // note2: any zero arguments are skipped // note3: gcd(0,0,..,0) is conventionaly set to 0 var args = arguments.length && (is_array(arguments[0]) || is_args(arguments[0])) ? arguments[0] : arguments, c = args.length, a, b, t, i, zeroes, Arithmetic = Abacus.Arithmetic, N = Arithmetic.num, O = Arithmetic.O, I = Arithmetic.I; if (0 === c) return O; i = 0; while (i= b) if (Arithmetic.lt(a, b)) { t=b; b=a; a=t; } while (!Arithmetic.equ(O, b)) { t = b; b = Arithmetic.mod(a, t); a = t; } } return a; } function lcm2(a, b) { var Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, aa = Arithmetic.abs(a), bb = Arithmetic.abs(b); if (Arithmetic.equ(aa, bb)) return sign(a) === sign(b) ? aa : Arithmetic.neg(aa); return Arithmetic.mul(Arithmetic.div(a, gcd(a, b)), b); } function lcm(/* args */) { // least common multiple // https://en.wikipedia.org/wiki/Least_common_multiple var args = arguments.length && (is_array(arguments[0]) || is_args(arguments[0])) ? arguments[0] : arguments, i, l = args.length, LCM, Arithmetic = Abacus.Arithmetic, O = Arithmetic.O; if (1 >= l) return 1===l ? args[0] : O; if (Arithmetic.equ(O, args[0]) || Arithmetic.equ(O, args[1])) return O; LCM = lcm2(args[0], args[1]); for (i=2; i= l) return 1===l ? args[0] : IntegerMod.Zero(2); if (args[0].equ(O) || args[1].equ(O)) return IntegerMod.Zero(args[0].m); LCM = nmax(args[0], args[1]); for (i=2; i= b) if (b.norm().gt(a.norm())) { t=b; b=a; a=t; } while (!b.equ(O)) { //a0 = a; b0 = b; r = a.mod(b); a = b; b = r; //if (a.equ(b0) && b.equ(a0)) break; // will not change anymore } } // normalize it if (a.real().abs().lt(a.imag().abs())) a = a.mul(Complex.Img()); if (a.real().lt(O)) a = a.neg(); return a; } function cxgcd(/* args */) { // Generalization of Extended GCD Algorithm for complex numbers var args = arguments.length && (is_array(arguments[0]) || is_args(arguments[0])) ? arguments[0] : arguments, k = args.length, i, Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, asign = Complex.One(), bsign = Complex.One(), t, a, b, a0, b0, a1, b1, a2, b2, qr, gcd; if (0 === k) return; a = args[0]; if (1 === k) { // normalize it if (a.real().abs().lt(a.imag().abs())) { a = a.mul(Complex.Img()); asign = asign.mul(Complex.Img()); } if (a.real().lt(O)) { a = a.neg(); asign = asign.neg(); } return [a, asign]; } else //if (2 <= k) { // recursive on number of arguments // compute xgcd on rest arguments and combine with current // based on recursive property: gcd(a,b,c,..) = gcd(a, gcd(b, c,..)) gcd = 2===k ? [args[1], Complex.One()] : cxgcd(slice.call(args, 1)); b = gcd[0]; // gcd with zero factor, take into account if (a.equ(O)) { // normalize it if (b.real().abs().lt(b.imag().abs())) { b = b.mul(Complex.Img()); asign = asign.mul(Complex.Img()); bsign = bsign.mul(Complex.Img()); } if (b.real().lt(O)) { b = b.neg(); asign = asign.neg(); bsign = bsign.neg(); } return array(gcd.length+1,function(i){ return 0===i ? b : (1===i ? asign : gcd[i-1].mul(bsign)); }); } else if (b.equ(O)) { // normalize it if (a.real().abs().lt(a.imag().abs())) { a = a.mul(Complex.Img()); asign = asign.mul(Complex.Img()); bsign = bsign.mul(Complex.Img()); } if (a.real().lt(O)) { a = a.neg(); asign = asign.neg(); bsign = bsign.neg(); } return array(gcd.length+1,function(i){ return 0===i ? a : (1===i ? asign : gcd[i-1].mul(bsign)); }); } a1 = Complex.One(); b1 = Complex.Zero(); a2 = Complex.Zero(); b2 = Complex.One(); for (;;) { //a0 = a; b0 = b; qr = a.divmod(b); a = qr[1]; a1 = a1.sub(qr[0].mul(a2)) b1 = b1.sub(qr[0].mul(b2)); if (a.equ(O)) { // normalize it if (b.real().abs().lt(b.imag().abs())) { b = b.mul(Complex.Img()); asign = asign.mul(Complex.Img()); bsign = bsign.mul(Complex.Img()); } if (b.real().lt(O)) { b = b.neg(); asign = asign.neg(); bsign = bsign.neg(); } a2 = a2.mul(asign); b2 = b2.mul(bsign); return array(gcd.length+1,function(i){ return 0===i ? b : (1===i ? a2 : gcd[i-1].mul(b2)); }); } qr = b.divmod(a); b = qr[1]; a2 = a2.sub(qr[0].mul(a1)); b2 = b2.sub(qr[0].mul(b1)); if (b.equ(O)) { // normalize it if (a.real().abs().lt(a.imag().abs())) { a = a.mul(Complex.Img()); asign = asign.mul(Complex.Img()); bsign = bsign.mul(Complex.Img()); } if (a.real().lt(O)) { a = a.neg(); asign = asign.neg(); bsign = bsign.neg(); } a1 = a1.mul(asign); b1 = b1.mul(bsign); return array(gcd.length+1, function(i){ return 0===i ? a : (1===i ? a1 : gcd[i-1].mul(b1)); }); } /*if (a.equ(a0) && b.equ(b0)) { // will not change anymore if (a.real().abs().lt(a.imag().abs())) { a = a.mul(Complex.Img()); asign = asign.mul(Complex.Img()); bsign = bsign.mul(Complex.Img()); } if (a.real().lt(O)) { a = a.neg(); asign = asign.neg(); bsign = bsign.neg(); } a1 = a1.mul(asign); b1 = b1.mul(bsign); return array(gcd.length+1, function(i){ return 0===i ? a : (1===i ? a1 : gcd[i-1].mul(b1)); }); }*/ } } } function clcm2(a, b) { var Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, g = cgcd(a, b); return g.equ(O) ? g : a.div(g).mul(b); } function clcm(/* args */) { // least common multiple // https://en.wikipedia.org/wiki/Least_common_multiple var args = arguments.length && (is_array(arguments[0]) || is_args(arguments[0])) ? arguments[0] : arguments, i, l = args.length, LCM, O = Abacus.Arithmetic.O; if (1 >= l) return 1===l ? args[0] : Complex.Zero(); if (args[0].equ(O) || args[1].equ(O)) return Complex.Zero(); LCM = clcm2(args[0], args[1]); for (i=2; i= b) if (0 > PolynomialClass.Term.cmp(a.ltm(), b.ltm(), true)) { t=b; b=a; a=t; } while (!b.equ(O)) { //a0 = a; b0 = b; r = a.mod(b); a = b; b = r; //if (a.equ(b0) && b.equ(a0)) break; // will not change anymore } } // simplify, positive and monic a = a.monic(); return a; } function polyxgcd(/* args */) { // Generalization of Extended GCD Algorithm for univariate polynomials // https://en.wikipedia.org/wiki/Polynomial_greatest_common_divisor#B%C3%A9zout's_identity_and_extended_GCD_algorithm // should be a generalisation of number xgcd, meaning for constant polynomials should coincide with xgcd of respective numbers var args = arguments.length && (is_array(arguments[0]) || is_args(arguments[0])) ? arguments[0] : arguments, k = args.length, i, Arithmetic = Abacus.Arithmetic, PolynomialClass = Polynomial, are_const = true, O = Arithmetic.O, I = Arithmetic.I, asign, bsign, a, b, a0, b0, a1, b1, a2, b2, lead, qr, gcd, g, f, p, q, field; if (0 === k) return; a = args[0]; PolynomialClass = a[CLASS]; for (i=0; i= l) return 1===l ? args[0] : PolynomialClass.Zero(); PolynomialClass = args[0][CLASS]; if (args[0].equ(O) || args[1].equ(O)) return PolynomialClass.Zero(args[0].symbol, args[0].ring); LCM = polylcm2(args[0], args[1]); for (i=2; i dir) return null; // only forward if (first) { i = I; if (!Arithmetic.equ(I, n)) next = n; return INT ? new INT(I) : I; } if (next) { k = next; next = null; return INT ? new INT(k) : k; } i = Arithmetic.add(i, I); while (Arithmetic.lte(i,sqrn)) { if (Arithmetic.equ(O, Arithmetic.mod(n, i))) { n_i = Arithmetic.div(n, i); if (!Arithmetic.equ(n_i, i)) { // two distinct divisors next = n_i; } return INT ? new INT(i) : i; } i = Arithmetic.add(i, I); } return null; }); } } else { // time+space O(sqrt(n)) to find all distinct divisors of n (including 1 and n itself) sqrn = isqrt(n); for (i=I; Arithmetic.lte(i,sqrn); i=Arithmetic.add(i,I)) { if (Arithmetic.equ(O, Arithmetic.mod(n, i))) { n_i = Arithmetic.div(n, i); if (Arithmetic.equ(n_i, i)) { // one distinct divisor, add to small list (after current) node = new Node(i, D1, null); L1++; if (D1) D1.r = node; D1 = node; } else { // two distinct divisors, add to small list (after current) and add to large list (before current) node = new Node(i, D1, null); L1++; if (D1) D1.r = node; D1 = node; node = new Node(n_i, null, D2); L2++; if (D2) D2.l = node; D2 = node; } // take note of the start of the divisors list if (!list) list = D1; } } if (D1) { // connect the two lists (small then large) D1.r = D2; if (D2) D2.l = D1; } D1 = null; D2 = null; // return all divisors sorted from smaller to larger (traverse divisors list and return items in order) return array(L1+L2, function(){ var curr = list, divisor = curr.v; // get current list item list = curr.r; // shift list to next item in order from left to right curr.dispose(); // dispose previous list item if (list) list.l = null; return INT ? new INT(divisor) : divisor; }); } } function moebius(n) { // https://en.wikipedia.org/wiki/M%C3%B6bius_function var Arithmetic = Abacus.Arithmetic, N = Arithmetic.num, O = Arithmetic.O, I = Arithmetic.I, two = Arithmetic.II, three, five, seven, four, six, eight, ten, inc, i, p, p2, m; // use factorization of n p = factorize(n); m = p.length; for (i=0; i x_1 = t_0 + t_1 x_2 = -2 - 6*t_0 - 2*t_1 where 't_0' and 't_1' are any integers. Note that: 4*(2 + 3*t_0) + 6*(t_0 + t_1) + 3*(-2 - 6*t_0 - 2*t_1) = 2 for any integral values of 't_0', 't_1'; as required. This method is generalised for many variables, below. */ ab = [gcd(a[k-2], a[k-1])]; a[k-2] = Arithmetic.div(a[k-2], ab[0]); a[k-1] = Arithmetic.div(a[k-1], ab[0]); for (i=k-3; i>0; i--) { d = gcd(ab[0], a[i]); ab[0] = Arithmetic.div(ab[0], d); a[i] = Arithmetic.div(a[i], d); ab.unshift(d); } ab.push(a[k-1]); solutions = []; parameters = array(k, function(i){ return symbol+'_'+(i+1); }); b = Expr(b); for (i=0,l=ab.length; i b.length) b = b.concat(array(m-b.length, function(i){return O;})); // A*X = B <=> iref(A.t|I) = R|T <=> iif R.t*P = B has int solutions P => X = T.t*P tmp = a.t()/*.concat(Matrix.I(ring, k))*/.ref(true/*, [k, m]*/); ref = tmp[0]; aug = tmp[3]; pivots = tmp[1]; rank = pivots.length; Tt = aug/*ref.slice(0,m,-1,-1)*/.t(); Rt = ref/*ref.slice(0,0,k-1,m-1)*/.t(); p = new Array(k); free_vars = new Array(k-rank); // R.t*P can be easily solved by substitution for (i=0; i= rank) { free_vars[i-rank] = symbol+'_'+(i-rank+1); p[i] = Expr(MulTerm(SymbolTerm(free_vars[i-rank]), I)); // free variable } else { for (t=O,j=0; j k) // check if additional rows are satisfied by solution as well for (i=k; ix.length) x = x.concat(array(ns.nc-x.length, function(i){return x[x.length-1].split('_')[0]+'_'+(x.length+i+1);})); return array(bp.nr, function(i){ return Expr(array(ns.nc, function(j){ return MulTerm(SymbolTerm(x[j]), ns.val[i][j]); })).add(bp.val[i][0]); }); } } function solvelineqs(a, b, x) { // solve general arbitrary system of m linear inequalities in k variables // a11 x_1 + a12 x_2 + a13 x_3 + .. + a1k x_k <= b1, a21 x_1 + a22 x_2 + a23 x_3 + .. + a2k x_k <= b2,.. // where a is m x k-matrix of coefficients: [[a11, a12, a13, .. , a1k],..,[am1, am2, am3, .. , amk]] // and b is m-array right hand side factor (default [0,..,0]) // https://en.wikipedia.org/wiki/Fourier%E2%80%93Motzkin_elimination var rel0, rel, sol, k, m, i, j, l, p, n, z, pi, ni; if (!is_instance(a, Matrix)) a = Matrix(Ring.Q(), a); if (!a.nr || !a.nc || a.ring !== Ring.Q()) return null; b = Matrix(a.ring, b).col(0); k = a.nc; m = a.nr; if (!x) x = 'x'; if (is_string(x)) x = array(k, function(i){return x+'_'+(i+1);}); else if (is_array(x) && k>x.length) x = x.concat(array(k-x.length, function(i){return x[x.length-1].split('_')[0]+'_'+(x.length+i+1);})); rel0 = array(m, function(j){ return RelOp.LTE(Expr(a.row(j).map(function(v, i){return MulTerm(SymbolTerm(x[i]), v);})), Expr(b[j])); }); sol = []; rel = rel0.slice(); for (i=k-1; i>=0; i--) { p = []; n = [], z = []; rel.forEach(function(s){ var f = s.lhs.term(x[i]).c().sub(s.rhs.term(x[i]).c()), e = s.rhs.sub(s.rhs.term(x[i])).sub(s.lhs.sub(s.lhs.term(x[i]))); if (f.gt(0)) p.push(e.div(f)); else if (f.lt(0)) n.push(e.div(f)); else z.push(e); }); if (!p.length || !n.length) { l = z.length; rel = new Array(l); for (j=0; j x^2 + y^2 - z^2 = 0 // solution adapted from sympy/solvers/diophantine.py var Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, I = Arithmetic.I, J = Arithmetic.J, two = Arithmetic.II, k = a.length, index, solutions, sol, param, i, ith, L, ilcm, s, pos, neg, //z, symbol = is_string(with_param) && with_param.length ? with_param : 'i'; if (!k) return null; // NOTE: assume all coefficients are perfect squares and non-zero pos = a.filter(function(ai){return 1 === sign(ai);}).length; neg = a.filter(function(ai){return -1 === sign(ai);}).length; //z = k-pos-neg; if ((1===k) || (0===pos) || (0===neg)) // trivial solution: sum of (same sign) integer squares to be zero, all terms have to be zero return array(k, function(){return Expr(); /* zero */}); s = array(k, function(i){return isqrt(Arithmetic.abs(a[i]));}); if (k !== a.filter(function(ai,i){return Arithmetic.equ(Arithmetic.abs(ai), Arithmetic.mul(s[i], s[i]));}).length) // no general solution in integers, coefficients are not perfect squares, return trivial solution return array(k, function(){return Expr(); /* zero */}); param = array(k-1, function(i){return symbol+'_'+(i+1);}); if (2 === k) // different sign, parametrised solution: // a1^2 x1^2 = a2^2 x2^2 ==> x1 = a2*i_1, x2 = a1*i_1 return [ Expr(MulTerm(SymbolTerm(param[0]), s[1])), Expr(MulTerm(SymbolTerm(param[0]), s[0])) ]; // k >= 3 if (0 > sign(a[0])+sign(a[1])+sign(a[2])) a = a.map(function(ai){return Arithmetic.neg(ai); }); index = 0; for (i=0; i 0 && i === 0) || (index === 0 && i === 1)) ilcm = lcm(ilcm, s[i]); else ilcm = lcm(ilcm, Arithmetic.equ(O, Arithmetic.mod(s[i], two)) ? Arithmetic.div(s[i], two) : s[i]); } for (i=0; i y+1) { for (k = I,j = y+1; j < x; j++) k = add(k, pow2(n-j-1)); index = add(index, k); subset_lex_rank.mem[key] = index; } } } else { index = subset_lex_rank.mem[key]; } return index; } subset_lex_rank.mem = Obj(); function subset_bin_rank(n, x, y) { var Arithmetic = Abacus.Arithmetic; return n > x && 0 <= x ? Arithmetic.shl(Arithmetic.I, x) : Arithmetic.O; } function pow2(n) { if (is_instance(n, Integer)) return new n[CLASS](pow2(n.num)); else if (is_instance(n, Rational)) return new n[CLASS](pow2(n.num), pow2(n.den)); var Arithmetic = Abacus.Arithmetic; return Arithmetic.shl(Arithmetic.I, Arithmetic.num(n)); } function exp(n, k) { var Arithmetic = Abacus.Arithmetic, N = Arithmetic.num; k = is_instance(k, Integer) ? k.num : N(k); if (is_instance(n, Integer)) return new n[CLASS](exp(n.num, k)); else if (is_instance(n, Rational)) return new n[CLASS](exp(n.num, k), exp(n.den, k)); return Arithmetic.pow(N(n), k); } /*function prime_factorial(n) { // compute factorial by its prime factorization // eg https://janmr.com/blog/2010/10/prime-factors-of-factorial-numbers/ var Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, fac = Arithmetic.I, e, p, pp, d, i, l, primes_up_to_n = PrimeSieve(); // compute exponents for each prime of the prime factorisation of n! p = primes_up_to_n.next(); while (null!=p && Arithmetic.lte(p, n)) { e = O; pp = p; d = Arithmetic.div(n, pp); while (!Arithmetic.equ(O, d)) { e = Arithmetic.add(e, d); pp = Arithmetic.mul(pp, p); d = Arithmetic.div(n, pp); } if (!Arithmetic.equ(O, e)) fac = Arithmetic.mul(fac, Arithmetic.pow(p, e)); // get next prime up to n p = primes_up_to_n.next(); } primes_up_to_n.dispose(); return fac; }*/ function split_product(list, start, end) { var Arithmetic = Abacus.Arithmetic; if (start > end) return Arithmetic.I; if (start === end) return list[start]; var middle = ((start + end) >>> 1); return Arithmetic.mul(split_product(list, start, middle), split_product(list, middle+1, end)); } function dsc_factorial(n) { // divide-swing-conquer fast factorial computation // https://oeis.org/A000142/a000142.pdf var Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, I = Arithmetic.I, two = Arithmetic.II, three = Arithmetic.num(3), swing, odd_factorial, bits, primes, sieve; swing = function swing(m, primes) { var s, d, e, g, factors, prime, p, q, i; if (Arithmetic.lt(m, 4)) return ([I,I,I,three])[Arithmetic.val(m)]; s = bisect(primes, Arithmetic.add(I, isqrt(m)), -1, null, null, Arithmetic.lt); d = bisect(primes, Arithmetic.add(I, Arithmetic.div(m, three)), -1, null, null, Arithmetic.lt); e = bisect(primes, Arithmetic.add(I, Arithmetic.div(m, two)), -1, null, null, Arithmetic.lt); g = bisect(primes, Arithmetic.add(I, m), -1, null, null, Arithmetic.lt); factors = primes.slice(e, g).concat(primes.slice(s, d).filter(function(p){return Arithmetic.equ(I, Arithmetic.mod(Arithmetic.div(m, p), two));})); for (i=1; i 0: D(n,k) = C(n,k) D(n-k) if (Arithmetic.lte(n, 12)) return Arithmetic.equ(n, O) ? I : (Arithmetic.lte(n, I) ? O : NUM(([1,2,9,44,265,1854,14833,133496,1334961,14684570,176214841])[VAL(sub(n, two))])); key = '!'+String(n); if (null == factorial.mem2[key]) { //factorial.mem2[key] = Math.floor((factorial(n)+1)/Math.E); /*factorial.mem2[key] = operate(function(N, n){ return add(n&1 ? J : I, mul(N,n)); }, I, null, 3, n);*/ if (Arithmetic.gt(n, 10000)) { for (res=O,f=I,i=O; Arithmetic.lte(i, n); i=add(i, I)) { res = add(res, mul(f, mul(factorial(n, i), factorial(sub(n, i))))); f = Arithmetic.neg(f); } } else { // recursive and memoized // derangement sub-factorial D(n) = n D(n-1) + (-1)^n = (n-1) (D(n-1) + D(n-2)) = !n = [(n!+1)/e] res = add(Arithmetic.equ(O, mod(n, two)) ? I : J, mul(factorial(sub(n, I), false), n)); } // memoize only up to MAXMEM results if (Arithmetic.lt(n, MAXMEM)) factorial.mem2[key] = res; } else { res = factorial.mem2[key]; } } else if (true === m) { // involution factorial = I(n) = I(n-1) + (n-1) I(n-2) // http://oeis.org/A000085 // I(n) = \sum_{k=0}^{\lfloor n/2 \rfloor}\binom{n}{2k}\frac{(2k)!}{k!2^k} if (Arithmetic.lte(n, 18)) return Arithmetic.lt(n, O) ? O : NUM(([1,1,2,4,10,26,76,232,764,2620,9496,35696,140152,568504,2390480,10349536,46206736,211799312,997313824])[VAL(n)]); key = 'I'+String(n); if (null == factorial.mem2[key]) { // recursive and memoized // involution factorial = I(n) = I(n-1) + (n-1) I(n-2) res = add(factorial(sub(n, I), true), mul(factorial(sub(n, two), true), sub(n, I))); // memoize only up to MAXMEM results if (Arithmetic.lt(n, MAXMEM)) factorial.mem2[key] = res; } else { res = factorial.mem2[key]; } } else if (is_array(m)) { // https://en.wikipedia.org/wiki/Multinomial_theorem // multinomial = n!/m1!..mk! if (!m.length) return Arithmetic.lt(n, O) ? O : factorial(n); else if (Arithmetic.lt(n, O)) return O; if (is_array(m[0])) { m = m[0]; if (!m.length) return Arithmetic.lt(n, O) ? O : factorial(n); else if (1 === m.length) return factorial(n, m[0]); res = operate(function(N, mk){return add(N, mk);}, O, m); if (Arithmetic.equ(res, O)) return n; else if (Arithmetic.gt(res, n)) return O; key = String(n)+'@'+mergesort(m.map(String),1,true).join(',')+'@'; if (null == factorial.mem3[key]) { i = sub(res, I); res = I; while (Arithmetic.gte(i, O)) { res = mul(res, sub(n, i)); i = sub(i, I); } res = operate(function(N, mk){return div(N, factorial(mk));}, res, m); // memoize only up to MAXMEM results if (Arithmetic.lt(n, MAXMEM)) factorial.mem3[key] = res; } else { res = factorial.mem3[key]; } } else { key = String(n)+'@'+mergesort(m.map(String),1,true).join(','); if (null == factorial.mem3[key]) { res = operate(function(N, mk){return div(N, factorial(mk));}, factorial(n), m); // memoize only up to MAXMEM results if (Arithmetic.lt(n, MAXMEM)) factorial.mem3[key] = res; } else { res = factorial.mem3[key]; } } } else if (Arithmetic.isNumber(m) || is_instance(m, Integer)) { m = is_instance(m, Integer) ? m.num : NUM(m); if (Arithmetic.lt(m, O)) { // selections, ie m!C(n,m) = n!/(n-m)! = (n-m+1)*..(n-1)*n if (Arithmetic.lte(n, Arithmetic.neg(m))) return Arithmetic.equ(n, Arithmetic.neg(m)) ? factorial(n) : O; key = String(n)+'@'+String(m); if (null == factorial.mem3[key]) { i = add(n, m); if (Arithmetic.gt(sub(n, i), 500)) { res = div(factorial(n), factorial(i)); } else { i = add(i, I); res = i; while (Arithmetic.lt(i, n)) { i = add(i, I); res = mul(res, i); } } // memoize only up to MAXMEM results if (Arithmetic.lt(n, MAXMEM)) factorial.mem3[key] = res; } else { res = factorial.mem3[key]; } } else { // https://en.wikipedia.org/wiki/Binomial_coefficient // binomial = C(n,m) = C(n-1,m-1)+C(n-1,m) = n!/m!(n-m)! if (Arithmetic.lt(m, O) || Arithmetic.lt(n, O) || Arithmetic.gt(m, n)) return O; if (Arithmetic.lt(n, mul(m, two))) m = sub(n, m); // take advantage of symmetry if (Arithmetic.equ(m, O) || Arithmetic.equ(n, I)) return I; else if (Arithmetic.equ(m, I)) return n; key = String(n)+'@'+String(m); if (null == factorial.mem3[key]) { // recursive and memoized // binomial = C(n,m) = C(n-1,m-1)+C(n-1,m) = n!/m!(n-m)! if (Arithmetic.lte(n, 20)) { res = add(factorial(sub(n, I), sub(m, I)), factorial(sub(n, I), m));/*div(factorial(n,-m), factorial(m))*/ } else if (Arithmetic.isDefault()) { res = stdMath.round(operate(function(Cnm,i){ // this is faster and will not overflow unnecesarily for default arithmetic return Cnm*(1+n/i); }, (n=n-m)+1, null, 2, m)); } else { i = sub(n, m); if (Arithmetic.gt(sub(n, i), 500)) { res = div(factorial(n), mul(factorial(m), factorial(i))); } else { i = add(i, I); res = i; while (Arithmetic.lt(i, n)) { i = add(i, I); res = mul(res, i); } res = div(res, factorial(m)); } } // memoize only up to MAXMEM results if (Arithmetic.lt(n, MAXMEM)) factorial.mem3[key] = res; } else { res = factorial.mem3[key]; } } } return res; } factorial.mem1 = Obj(); factorial.mem2 = Obj(); factorial.mem3 = Obj(); function derange_k_of_n(n, k) { // https://math.stackexchange.com/questions/4192567/count-permutations-where-some-items-should-be-deranged-while-rest-can-be-placed var Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, I = Arithmetic.I, J = Arithmetic.J, NUM = Arithmetic.num, add = Arithmetic.add, sub = Arithmetic.sub, mul = Arithmetic.mul, key, res, i, f, nk, MAXMEM = Abacus.Options.MAXMEM; if (is_instance(n, Integer)) return new n[CLASS](derange_k_of_n(n.num, k)); n = NUM(n); k = is_instance(k, Integer) ? k.num : NUM(k); if (Arithmetic.lt(n, O) || Arithmetic.lt(k, O) || Arithmetic.gt(k, n)) return O; if (Arithmetic.equ(k, O)) return factorial(n); if (Arithmetic.equ(k, n)) return factorial(n, false); key = String(n)+','+String(k); if (null == derange_k_of_n.mem[key]) { res = O; nk = sub(n, k); if (Arithmetic.lt(nk, k)) { // \sum\limits_{i=0}^{n-k} {{n-k} \choose i} \ !(k+i) for (i=O; Arithmetic.lte(i, nk); i=add(i, I)) { res = add(res, mul(factorial(nk, i), factorial(add(k, i), false))); } } else { // \sum\limits_{i=0}^k\binom{k}{i}(-1)^i(n-i)! for (f=I,i=O; Arithmetic.lte(i, k); i=add(i, I)) { res = add(res, mul(f, mul(factorial(k, i), factorial(sub(n, i))))); f = Arithmetic.neg(f); } } // memoize only up to MAXMEM results if (Arithmetic.lt(n, MAXMEM)) derange_k_of_n.mem[key] = res; } else { res = derange_k_of_n.mem[key]; } return res; } derange_k_of_n.mem = Obj(); function derange_rank(n, y, i, k, unvisited/*indexOf*/) { var Arithmetic = Abacus.Arithmetic, count = Arithmetic.O, x; /*for (x=0; xi && xi && x.index n-1 */ catalan.mem[key] = res; } else { res = div(factorial(mul(n, two), n), add(n, I)) /*operate(function(c, k){ return div(mul(c, k+n), k); }, I, null, 2, n)*/; } } else { res = catalan.mem[key]; } return res; } catalan.mem = Obj(); function bell(n) { var Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, I = Arithmetic.I, NUM = Arithmetic.num, VAL = Arithmetic.val, add = Arithmetic.add, sub = Arithmetic.sub, mul = Arithmetic.mul, key, res = O, i, MAXMEM = Abacus.Options.MAXMEM; // https://en.wikipedia.org/wiki/Bell_number // https://en.wikipedia.org/wiki/Bell_triangle // http://fredrikj.net/blog/2015/08/computing-bell-numbers/ // bell numbers B(n) = SUM[k:0->n-1] (C(n-1,k) B(k)) if (is_instance(n, Integer)) return new n[CLASS](bell(n.num)); n = NUM(n); if (Arithmetic.lte(n, 14)) return Arithmetic.lt(n, O) ? O : NUM(([1,1,2,5,15,52,203,877,4140,21147,115975,678570,4213597,27644437,190899322])[VAL(n)]); key = String(n); if (null == bell.mem[key]) { res = O; i = O; n = sub(n, I); while (Arithmetic.lte(i, n)) { res = add(res, mul(factorial(n, i), bell(i))); i = add(i, I); } // memoize only up to MAXMEM results if (Arithmetic.lt(n, MAXMEM)) bell.mem[key] = res; } else { res = bell.mem[key]; } return res; } bell.mem = Obj(); function fibonacci(n) { var Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, I = Arithmetic.I, two = Arithmetic.II, NUM = Arithmetic.num, VAL = Arithmetic.val, k, f1, f0, key, res = O, MAXMEM = Abacus.Options.MAXMEM; // http://en.wikipedia.org/wiki/Fibonacci_number // fibonacci numbers F(n) = F(n-1) + F(n-2) if (is_instance(n, Integer)) return new n[CLASS](fibonacci(n.num)); n = NUM(n); if (Arithmetic.lte(n, 36)) return Arithmetic.lt(n, O) ? O : NUM(([0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368,75025,121393,196418,317811,514229,832040,1346269,2178309,3524578,5702887,9227465,14930352])[VAL(n)]); key = String(n); if (null == fibonacci.mem[key]) { // recursive and memoized // fibonacci numbers F(n) = F(n-1) + F(n-2) //f1 = fibonacci(n-1); f0 = fibonacci(n-2); //res = Arithmetic.add(f1,f0); // https://www.nayuki.io/page/fast-fibonacci-algorithms // recursive and memoized and fast doubling // fibonacci numbers F(2k) = F(k)(2F(k+1)-F(k)), F(2k+1) = F(k+1)^2 + F(k)^2 k = Arithmetic.div(n, two); f1 = fibonacci(Arithmetic.add(k, I)); f0 = fibonacci(k); if (Arithmetic.equ(O, Arithmetic.mod(n, two))) // 2k res = Arithmetic.mul(f0, Arithmetic.sub(Arithmetic.mul(f1, Arithmetic.II), f0)); else // 2k+1 res = Arithmetic.add(Arithmetic.mul(f1, f1), Arithmetic.mul(f0, f0)); // memoize only up to MAXMEM results if (Arithmetic.lt(n, MAXMEM)) fibonacci.mem[key] = res; } else { res = fibonacci.mem[key]; } return res; } fibonacci.mem = Obj(); function polygonal(n, k) { // https://en.wikipedia.org/wiki/Figurate_number // https://en.wikipedia.org/wiki/Polygonal_number // https://en.wikipedia.org/wiki/Triangular_number // https://en.wikipedia.org/wiki/Square_number // https://en.wikipedia.org/wiki/Pentagonal_number // https://en.wikipedia.org/wiki/Hexagonal_number // https://en.wikipedia.org/wiki/Heptagonal_number // https://en.wikipedia.org/wiki/Octagonal_number // https://en.wikipedia.org/wiki/Nonagonal_number // https://en.wikipedia.org/wiki/Decagonal_number var Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, I = Arithmetic.I, two = Arithmetic.II, NUM = Arithmetic.num, number; if (is_instance(k, Integer)) k = k.num; k = NUM(k); if (Arithmetic.lt(k, 3)) return null; if (is_instance(n, Integer)) return new n[CLASS](polygonal(n.num, k)); n = NUM(n); number = Arithmetic.div(Arithmetic.mul(n, Arithmetic.sub(Arithmetic.mul(n, Arithmetic.sub(k, two)), Arithmetic.sub(k, 4))), two); return number; } function sum_nk(n, k) { // https://brilliant.org/wiki/sum-of-n-n2-or-n3/ var Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, I = Arithmetic.I, add = Arithmetic.add, sub = Arithmetic.sub, mul = Arithmetic.mul, div = Arithmetic.div, pow = Arithmetic.pow, NUM = Arithmetic.num, sum = O, m, f, k1, key, MAXMEM = Abacus.Options.MAXMEM; if (is_instance(n, Integer)) return new n[CLASS](polygonal(n.num, k)); n = NUM(n); if (is_instance(k, Integer)) k = k.num; k = NUM(k); if (Arithmetic.lte(n, O) || Arithmetic.lt(k, O)) return sum; if (Arithmetic.equ(k, O)) { sum = n; } else if (Arithmetic.equ(k, I)) { sum = div(mul(n, add(n, I)), 2); } else if (Arithmetic.equ(k, 2)) { sum = div(mul(n, mul(add(n, I), add(mul(n, 2), I))), 6); } else if (Arithmetic.equ(k, 3)) { sum = div(mul(pow(n, 2), pow(add(n, I), 2)), 4); } else { key = String(n)+','+String(k); if (null == sum_nk.mem[key]) { if (Arithmetic.lt(k, n)) { /* compute it using recurrence relation on k s_{k,n} = \sum\limits_{i=1}^n i^k. n^{k+1} = \binom{k+1}1 s_{k,n} - \binom{k+1}2 s_{k-1,n} + \binom{k+1}3 s_{k-2,n} - \cdots + (-1)^{k-1} \binom{k+1}{k} s_{1,n} + (-1)^k n */ m = I; f = I; k1 = add(k, I); sum = pow(n, k1); while (Arithmetic.lte(m, k)) { sum = add(sum, mul(f, mul(factorial(k1, add(m, I)), sum_nk(n, sub(k, m))))); m = add(m, I); f = Arithmetic.neg(f); } sum = div(sum, k1); } else { // compute it directly, on iterating over n while (Arithmetic.gt(n, O)) { sum = add(sum, pow(n, k)); n = sub(n, I); } } // memoize only up to MAXMEM results if (Arithmetic.lt(n, MAXMEM)) sum_nk.mem[key] = sum; } else { sum = sum_nk.mem[key]; } } return sum; } sum_nk.mem = Obj(); // combinatorial utilities, available as static methods of respective objects function kronecker(/* var args here */) { var args = arguments, nv = args.length, k, a, r, l, i, j, vv, tensor, tl, kl, product; if (!nv) return []; if (true === args[0]) { // flat tensor product for (kl=args[1].length,k=2; k=0; a--) { l = args[ a ].length; i = r % l; r = ~~(r / l); vv = args[ a ][ i ]; if (is_array(vv) || is_args(vv)) { // kronecker can be re-used to create higher-order products // i.e kronecker(alpha, beta, gamma) and kronecker(kronecker(alpha, beta), gamma) // should produce exactly same results for (j=vv.length-1; j>=0; j--) tensor[nv-(++tl)] = vv[ j ]; } else { tensor[nv-(++tl)] = vv; } } product[ k ] = tensor; } } return product; } function cartesian(/* var args here */) { // direct sum product, since the final dimensions = sum of component dimensions it is like cartesian product // whereas tensor product has final dimensions = product of component dimensions var v = arguments, nv = v.length, n=0, k, j; for (j=0; j= k+v[j].length) k+=v[j++].length; return k+v[j][i-k]; }); } function conditional_combinatorial_tensor(v, value_conditions, extra_conditions) { var k, kl, a, r, l, i, vv, nv = v.length, v0, v1, tensor, t0, t1, ok, nvalid, product, p, pv, pe, pea, pl, npv, seen = null, valid = null, invalid, expr, e, el; if (!nv) return []; if (is_callable(extra_conditions)) { valid = extra_conditions; extra_conditions = true; } else { extra_conditions = false; } if (!(V_EQU===value_conditions || V_DIFF===value_conditions || V_INC===value_conditions || V_DEC===value_conditions || V_NONINC===value_conditions || V_NONDEC===value_conditions)) { value_conditions = false; } pe = new Array(nv); pea = []; pl = 0; pv = []; for (kl=1,k=0; k=kl) return []; } } if (!pv.length) return []; product = new Array(kl); nvalid = 0; t1 = nv-1; npv = pv.length-1; // O(kl), count only necessary values, minus any outliers (as few as possible) for (k=0; k=0; a--) { p = pv[a]; l = v[p].length; i = r % l; r = ~~(r / l); tensor[p] = v[p][i]; } // evaluate expressions which are autonomous, do not depend on any position for (a=0,pl=pea.length; a=0; t0--) { v0 = tensor[t0]; if ( (null == v0) || isNaN(v0) || (V_EQU === value_conditions && v1 !== v0) || (V_DIFF === value_conditions && 1 === seen[v0]) || (V_INC === value_conditions && v0 >= v1) || (V_DEC === value_conditions && v0 <= v1) || (V_NONINC === value_conditions && v0 < v1) || (V_NONDEC === value_conditions && v0 > v1) || (extra_conditions && !valid(tensor,t0,t1)) ) { invalid = true; break; } if (V_DIFF === value_conditions) seen[v0] = 1; v1 = v0; } } } if (invalid) continue; product[ nvalid++ ] = tensor; } // truncate if needed if (product.length > nvalid) product.length = nvalid; return product; } function gen_combinatorial_data(n, data, pos, value_conditions, options) { options = options || {}; pos = pos || array(data.length||0, 0, 1); // conditions: ALGEBRAIC(STRING EXPR) AND/OR BOOLEAN(POSITIVE / NEGATIVE) => [values] per position // NOTE: needs at least one non-autonomous expression or one range of values, else will return empty set var min = null==options.min ? 0 : options.min, max = null==options.max ? n-1 : options.max, nn = max-min+1, D = data, m, d, i, a, j, pi, l = D.length, none = false, pos_ref, is_valid, p1, p2, expr, algebraic = [], missing = [], ref = {}, in_range = function in_range(x){ return min<=x && x<=max; }, additional_conditions; data = []; none = false; for (pi=0,i=0; im[1]) a = complement(n,array(m[0]-m[1]+1,m[1],1).filter(in_range)).reverse(); else a = complement(n,array(m[1]-m[0]+1,m[0],1).filter(in_range)); } else { a = complement(n,m[1].split(',').map(Number).filter(in_range)); } if (!a.length) { none = true; break; } data.push(a); } else if (m=d.match(in_set_re)) { if (0 < m[1].indexOf('..')) { m = m[1].split('..').map(Number); a = (m[0]>m[1]?array(m[0]-m[1]+1,m[0],-1):array(m[1]-m[0]+1,m[0],1)).filter(in_range); } else { a = m[1].split(',').map(Number).filter(in_range); } if (!a.length) { none = true; break; } data.push(a); } else { is_valid = true; pos_ref = []; expr = null; d = d.replace(pos_re, function(m, d){ var posref = parseInt(d, 10), varname = 'v'+String(posref); if (isNaN(posref) || !in_range(posref)) is_valid = false; if (is_valid && (-1 === pos_ref.indexOf(posref))) pos_ref.push(posref); return varname; }); if (!is_valid) { if (pos) pos.splice(pi--, 1); continue; } pos_ref.sort(sorter()); try{ expr = new Function(pos_ref.map(function(p){return 'v'+String(p);}).join(','),'return Math.floor('+d+');'); } catch(e){ expr = null; } if (!is_callable(expr)) { if (pos) pos.splice(pi--, 1); continue; } for (j=0; jex || ex>max) return false; } return true; }); if (!a.length) { none = true; break; } else data[m[1][j]] = a; } } if (none) break; } } if (none) return []; // check value conditions if ('=' === value_conditions) value_conditions = V_EQU; else if (('!=' === value_conditions) || ('<>' === value_conditions)) value_conditions = V_DIFF; else if ('<' === value_conditions) value_conditions = V_INC; else if (('<=' === value_conditions) || ('=<' === value_conditions)) value_conditions = V_NONDEC; else if ('>' === value_conditions) value_conditions = V_DEC; else if (('>=' === value_conditions) || ('=>' === value_conditions)) value_conditions = V_NONINC; else value_conditions = false; // check additional conditions additional_conditions = is_callable(options.extra_conditions) ? function(v,i0,i1){ var v0 = v[i0]; if ( // check in range (min>v0 || v0>max) || // when strictly increasing sequence then value at pos i cannot be less than i since it has to accomodate the rest values as well before it, complementary for strictly decreasing sequence (for strictly decreasing sequence we do not know the number of elements that come after unlike for strictly increasing sequence where we can know, but as a workaround we can add last possible position in conditions with all possible values simply as a hint/clue on what is last possible position) // (assume values in range 0..n-1 for positions 0..n-1 or reverse) (V_INC === value_conditions && pos[i0]>v0) || (V_DEC === value_conditions && pos[pos.length-1]-pos[i0]>v0) ) return false return options.extra_conditions(v,i0,i1); } : function(v,i0,i1){ var v0 = v[i0]; if ( // check in range (min>v0 || v0>max) || // when strictly increasing sequence then value at pos i cannot be less than i since it has to accomodate the rest values as well before it, complementary for strictly decreasing sequence (for strictly decreasing sequence we do not know the number of elements that come after unlike for strictly increasing sequence where we can know, but as a workaround we can add last possible position in conditions with all possible values simply as a hint/clue on what is last possible position) // (assume values in range 0..n-1 for positions 0..n-1 or reverse) (V_INC === value_conditions && pos[i0]>v0) || (V_DEC === value_conditions && pos[pos.length-1]-pos[i0]>v0) ) return false return true; }; // compute valid combinatorial data satisfying conditions return true === options.lazy ? data : conditional_combinatorial_tensor(data, value_conditions, additional_conditions); } function summation(a, b, Arithmetic, do_subtraction) { // O(max(n1,n2)) var i, j, n1 = a.length, n2 = b.length, c; if (true===Arithmetic) { c = array(stdMath.max(n1, n2), do_subtraction ? function(i){ return i >= n1 ? b[i].neg() : (i >= n2 ? a[i] : a[i].sub(b[i])); } : function(i){ return i >= n1 ? b[i] : (i >= n2 ? a[i] : a[i].add(b[i])); }); } else if (Arithmetic) { c = array(stdMath.max(n1, n2), do_subtraction ? function(i){ return i >= n1 ? Arithmetic.neg(b[i]) : (i >= n2 ? a[i] : Arithmetic.sub(a[i], b[i])); } : function(i){ return i >= n1 ? b[i] : (i >= n2 ? a[i] : Arithmetic.add(a[i], b[i])); }); } else { c = array(stdMath.max(n1, n2), do_subtraction ? function(i){ return i >= n1 ? -b[i] : (i >= n2 ? a[i] : a[i] - b[i]); } : function(i){ return i >= n1 ? b[i] : (i >= n2 ? a[i] : a[i] + b[i]); }); } return c; } function convolution(a, b, Arithmetic) { // O(n1*n2), can be done a bit faster // 1. by using FFT multiplication, not implemented here // 2. by Divide&Conquer and using eg. Strassen multiplication, not implemented here var i, j, n1 = a.length, n2 = b.length, c; if (true===Arithmetic) { c = array(n1+n2-1, function(){return 0;}); for (i=0; i k) c.length = k; // truncate if needed return c; } function multiplication_sparse(a, b, TermClass, ring) { // O(log(n1)*n1*n2) // assume a, b are arrays of **non-zero only** coeffs of MulTerm class of coefficient and exponent already sorted in exponent decreasing order // merge terms by efficient merging and produce already sorted order c // eg http://www.cecm.sfu.ca/~mmonagan/teaching/TopicsinCA11/johnson.pdf // and https://www.researchgate.net/publication/333182217_Algorithms_and_Data_Structures_for_Sparse_Polynomial_Arithmetic // and https://www.semanticscholar.org/paper/High-Performance-Sparse-Multivariate-Polynomials%3A-Brandt/016a97690ecaed04d7a60c1dbf27eb5a96de2dc1 TermClass = TermClass===MultiPolyTerm ? MultiPolyTerm : UniPolyTerm; ring = ring || Ring.Q(); var k, t, n1, n2, c, f, max, heap, O = Abacus.Arithmetic.O; if (a.length > b.length){ t=a; a=b; b=t;} // swap to achieve better performance n1 = a.length; n2 = b.length; c = new Array(n1*n2); if (0 k+1) c.length = k+1; // truncate if needed } return c; } function division_sparse(a, b, TermClass, q_and_r, ring) { // sparse polynomial reduction/long division // https://www.semanticscholar.org/paper/High-Performance-Sparse-Multivariate-Polynomials%3A-Brandt/016a97690ecaed04d7a60c1dbf27eb5a96de2dc1 q_and_r = (true===q_and_r); TermClass = TermClass===MultiPolyTerm ? MultiPolyTerm : UniPolyTerm; ring = ring || Ring.Q(); var na = a.length, nb = b.length, O = Abacus.Arithmetic.O, heap = Heap([], "max", function(a,b){return TermClass.cmp(a.term, b.term);}), q = [], r = [], k = 0, d, res, Q, b0; if (!b.length) return null; b0 = b[0].cast(ring); while ((d=heap.peek()) || kTermClass.cmp(d.term, a[k]))) { res = a[k].cast(ring); k++; } else if (kd.n) heap.replace({term:d.Q.mul(b[d.n].cast(ring)), n:d.n+1, Q:d.Q}); else heap.pop(); k++; //if (res.equ(O)) continue; // zero coefficient, skip } else { res = d.term.neg(); if (nb>d.n) heap.replace({term:d.Q.mul(b[d.n].cast(ring)), n:d.n+1, Q:d.Q}); else heap.pop(); } if (res.equ(O)) continue; // zero coefficient, skip if (b0.divides(res)) { Q = res.div(b0); q = addition_sparse(q, [Q], TermClass, false, ring); if (nb>1) heap.push({term:Q.mul(b[1].cast(ring)), n:2, Q:Q}); } else if (q_and_r) { r = addition_sparse(r, [res], TermClass, false, ring); } } heap.dispose(); return q_and_r ? [q, r] : q; } function complement(n, item, sort/*, dupl*/) { if ((null == item) || (!item.length) || (1>=item.length)) return 1===item.length ? array(n-1, function(i){return i= n) return []; var binary = array(n, 0, 0), i, l = item.length; for (n=n-1,i=0; i= n) { conjugate = item.slice(); } else { // get the associated n-composition of the complement(conjugate) of the associated (n-1)-subset conjugate = subset2composition(complement(n-1, composition2subset(item, l-1, dir))); // add the remainder if (0 < (n=n-operate(addn,0,conjugate))) conjugate.push(n); // if reflected, get the reflected composition if (0>dir) reflection(conjugate,conjugate); } } else { // http://mathworld.wolfram.com/ConjugatePartition.html var i, ii, j, jj, p, a = 1, b = 0, d = 0, push = "push"; if (0>dir) { a = -a; b = l-1-b; push = "unshift"; } if (is_array(item[b])) { // multiplicity(packed) representation p = item[b]; conjugate = [[p[1], p[0]]]; i = 0; for (j=1,jj=a+b; jdir ? 0 : i; if (p[1] === conjugate[ii][0]) { // same part increase multiplicity conjugate[ii][1] += p[0]; } else { // swap part with multiplicity conjugate[push]([p[1], p[0]]); i++; } } } else { // standard(unpacked) representation n = item[b]; conjugate = array(n, 1, 0); if (0>dir) d = n-1-d; for (j=1,jj=a+b; j 0)) { conjugate[ii]++; p--; i++; ii+=a; } } } } return conjugate; } function packpartition(partition, dir) { if (null == partition) return null; var packed = [], i, j, l = partition.length, reflected = -1 === dir, a = 1, b = 0, push = "push", last, part; if (reflected) { a = -a; b = l-1-b; push = "unshift"; } for (last=partition[b],part=[last, 1],i=1; i S.indexOf(si) && 0 > I.indexOf(si)) set.push(si); return set; }, []); if (set.length) return p.push(set); return p; }, []), S, I]; } function separateST(item, S, T) { return [item.reduce(function(p, set){ set = set.reduce(function(set, si){ if (0 > S.indexOf(si) && 0 > T.indexOf(si)) set.push(si); return set; }, []); if (set.length) return p.push(set); return p; }, []), S, I]; } function combineIS(item, S, I) { return [item.reduce(function(p, set){ set = set.reduce(function(set, si){ if (0 > S.indexOf(si) && 0 > I.indexOf(si)) set.push(si); return set; }, []); if (set.length) return p.push(set); return p; }, []), S, I]; } function combineST(item, S, T) { return [item.reduce(function(p, set){ set = set.reduce(function(set, si){ if (0 > S.indexOf(si) && 0 > T.indexOf(si)) set.push(si); return set; }, []); if (set.length) return p.push(set); return p; }, []), S, I]; }*/ function conjugatesetpartition(item, n) { // adapted from https://arxiv.org/abs/math/0508052 if (null == item) return null; var congugate = null; return conjugate; } function permutation2matrix(matrix, permutation, transposed) { var i, j, n = permutation.length, n2 = n*n; matrix = matrix || new Array(n2); for (i=0,j=0; i= n) { j=0; i+=n; } } if (true === transposed) for (i=0; i= n) { j=0; i++; } } } else { for (i=0,j=0; i= n) { j=0; i++; } } } return permutation; } function multiset(m, n, dir) { var nm = m ? m.length : 0, dk = 1, k = 0, ki = 0, mk = ki < nm ? m[ki]||1 : 1; if (-1 === dir){ dk = -1; k = (nm||n)-1; } return operate(function(p,i){ if (0 >= mk) { ki++; k+=dk; mk = ki>> 1) << 1]; // 2) increase the value stored at the current node. T[node] += 1; // 3) move-up the tree node >>>= 1; } T[node] += 1; inv[i] = ctr; return inv; }, inversion||new Array(n), permutation); } function inversion2permutation(permutation, inversion, N) { // O(n log n) inversion computation // "Efficient Algorithms to Rank and Unrank Permutations in Lexicographic Order", Blai Bonet (http://ldc.usb.ve/~bonet/reports/AAAI08-ws10-ranking.pdf) var n = inversion.length, k = stdMath.ceil(log2(N||n)), i, i2, j, twok = 1 << k, Tl = (1<<(1+k))-1, T = new Array(Tl); for (i=0; i<=k; i++)for (j=1,i2=1<= T[node]) { // If the next node is the right child, then the value of the left child is subtracted from digit digit -= T[node]; node++; } } T[node] = 0; perm[i] = node - twok; return perm; }, permutation||new Array(n), inversion); } function permutation2count(count, permutation, dir) { // O(n) count computation K(\sigma)_i = \#\{j > i : \sigma_j > i\} // K(\sigma)_i = n-1-i-K'(\sigma)_i-1_{\sigma_{i} > i}, K'(\sigma)_i = \#\{j < i : \sigma_j > i\} (complement) /* https://cs.stackexchange.com/questions/142180/faster-algorithm-for-a-specific-inversion $$ |\{j>i : \sigma_j > i\}| = | \{ j> i+1 : \sigma_j > i+1 \} | + | \{ j > i : \sigma_j = i+1 \} | + 1_{\sigma_{i+1} > i+1} $$ The cardinality of second set is $1$ if there is some value $j'$ of $j>i$ such that $\sigma_{j'}=i+1$ and $0$ otherwise (there can be at most one such value $j'$). Rewrite it as: $\sum_{h > i} 1_{\sigma_h = i+1} = 1_{\sigma_{i+1} = i+1} + \sum_{h > i+1} 1_{\sigma_h = i+1} = 1_{\sigma_{i+1} = i+1} + \sum_{h > i+1} 1_{\min\{h, \sigma_h\} = i+1}$ Summing the above with the last term from the initial equation we have: $$ 1_{\sigma_{i+1} > i+1} + 1_{\sigma_{i+1} = i+1} + \sum_{h > i+1} 1_{\min\{h, \sigma_h\} = i+1} $$ At most one of the two first two terms can be $1$, hence this simplifies to: $$ 1_{\sigma_{i+1} \ge i+1} + \sum_{h > i+1} 1_{\min\{h, \sigma_h\} = i+1} = \sum_{h > i} 1_{\min\{h, \sigma_h\} = i+1} $$ Substituting $$ K(\sigma)_i = K(\sigma)_{i+1} + \sum_{h > i} 1_{\min\{h, \sigma_h\} = i+1}$$ Where the second term is exactly what we are writing in $A[i+1]$. */ var n = permutation.length, A = array(n, 0, 0), i; for (i=0; i i\} = n-i-1-K(\sigma)_i-1_{\sigma_i>i} count = operate(function(count,i){ count[i] = n-i-1-count[i]-(iy); j=j.prev) { unvisited.rem(j); for (k=j.prev; k && (k.index>=0); k=k.prev) { unvisited.rem(k); c = Arithmetic.add(c, Arithmetic.add(countswaps(n, k.index, j.index, unvisited), j.index+1= swaps.length) return c; if (y+1 === n) return Arithmetic.I; s0 = swaps[i][0]; s1 = swaps[i][1]; unvisited.rem(x); unvisited.rem(y); for (j=unvisited.last(); j && (j.index>y); j=j.prev) { b = false; unvisited.rem(j); for (k=j.prev; k && (k.index>=0); k=k.prev) { unvisited.rem(k); if (k.index===s0 && j.index===s1) { c = Arithmetic.add(Arithmetic.add(c, matchswaps(n, k.index, j.index, swaps, i+1, unvisited)), Arithmetic.I); b = true; } else { c = Arithmetic.add(c, Arithmetic.add(countswaps(n, k.index, j.index, unvisited), j.index+1y); j=j.prev) { b = false; unvisited.rem(j); for (k=j.prev; k && (k.index>=0); k=k.prev) { unvisited.rem(k); r2 = r; r = Arithmetic.add(r, Arithmetic.add(countswaps(n, k.index, j.index, unvisited), j.index+1y; j--) { for (k=j-1; k>=0; k--) { c = Arithmetic.add(c, Arithmetic.add(countswaps(n, k, j, unvisited), j+1x; k--) { c = Arithmetic.add(c, Arithmetic.add(countswaps(n, k, y, unvisited), y+1 1) { if (noref) { swaps = new Array(c-1); slen = 0; } for (j=c-1; j>=1; j--) swaps[slen++] = [cycle[0],cycle[j]]; } else { if (noref) swaps = []; } return noref ? swaps : slen; } function permutation2cycles(permutation, strict) { var n = permutation.length, i, cycles = new Array(n), current, cycle, min_cycle = true === strict ? 1 : 0, unvisited = ListSet(n), clen, cclen = 0; if (!n) return cycles; cycle = new Array(n); clen = 0; current = unvisited.first().index; unvisited.rem(current); cycle[clen++] = current; while (unvisited.first()) { current = permutation[ current ]; if (!unvisited.has(current)) { if (clen > min_cycle) { cycle.length = clen; // truncate cycles[cclen++] = cycle; } cycle = new Array(n); clen = 0; current = unvisited.first().index; } cycle[clen++] = current; unvisited.rem(current); } if (clen > min_cycle) { cycle.length = clen; // truncate cycles[cclen++] = cycle; } if (cclen < cycles.length) cycles.length = cclen; // truncate return cycles; } function cycles2permutation(cycles, n) { var permutation = array(n || (cycles.reduce(function(s, c){return stdMath.max(s, stdMath.max.apply(null, c)||0);}, 0)+1), 0, 1), i, j, k = cycles.length, ki, cycle; for (i=k-1; i>=0; i--) { cycle = cycles[i]; ki = cycle.length; if (1 < ki) { for (j=0; j+1 m ? function(ap, i){ ap[i] = i= k+pn) { k += pn; pn = permutations[++p].length; } return k + permutations[p][i-k]; }); } function is_permutation(perm, n) { n = n || perm.length; if (n !== perm.length) return false; var cnt = array(n, 0, 0), i, pi; // O(n) for (i=0; i pi) || (pi >= n) || (0 < cnt[pi])) return false; cnt[pi]++; } for (i=0; i pi) || (n <= pi) || (perm[pi] !== i)) return false; return true; } function is_kthroot(perm, k) { k = k || 1; if (1 > k) return false; var i, pi, m, n = perm.length; // O(kn) worst case for (i=0; i=k || (0 < (k%m))))) return false } return true; } function is_derangement(perm, kfixed, strict) { // O(n) kfixed = kfixed|0; for (var nfixed=0,n=perm.length,i=0; i kfixed) return false; } return true === strict ? nfixed === kfixed : true; } function is_cyclic/*_shift*/(perm) { // O(n) for (var n=perm.length,i=1,i0=perm[0]; i m) m = pi; // update max if (m <= i) return false; // prefix mapped to itself, not connected (is decomposable) } return true; } function is_kcycle(perm, kcycles, compare, fixed) { // O(n) if (!perm.length || 0>=kcycles) return false; fixed = false !== fixed; var n = perm.length, i, pi, ncycles, unvisited, done; ncycles = 0; done = false; unvisited = ListSet(n); i = unvisited.first().index; while (!done) { unvisited.rem(i); pi = perm[i]; if (i===pi || !unvisited.has(pi)) { // close cycle if (fixed || i!==pi) ncycles++; unvisited.rem(pi); // start next cycle if (unvisited.first()) i = unvisited.first().index; else done = true; } else { // follow cycle i = pi; } } return "<="===compare||"=<"===compare ? ncycles<=kcycles : (">="===compare||"=>"===compare ? ncycles>=kcycles : ncycles===kcycles); } function is_magic(square) { if (!square) return false; var n = square.length, n2 = n*n, i, j, k, summa_row = 0, summa_col = 0, summa_d1 = 0, summa_d2 = 0, summa = (n*n2+n)>>>1, seen = new Array(n2); for (i=0; i n2 || i !== seen[k-1][0] || 0 !== seen[k-1][1]) return false; summa_row = k; k = square[0][i]; if (!seen[k-1]) seen[k-1] = [0, i]; if (k < 1 || k > n2 || 0 !== seen[k-1][0] || i !== seen[k-1][1]) return false; summa_col = k; summa_d1 += square[i][i]; summa_d2 += square[i][n-1-i]; for (j=1; j n2 || i !== seen[k-1][0] || j !== seen[k-1][1]) return false; summa_row += k; k = square[j][i]; if (!seen[k-1]) seen[k-1] = [j, i]; if (k < 1 || k > n2 || j !== seen[k-1][0] || i !== seen[k-1][1]) return false; summa_col += k; } if ((summa_row !== summa) || (summa_col !== summa)) return false; } if ((summa_d1 !== summa) || (summa_d2 !== summa)) return false; return true; } function is_latin(square) { if (!square) return false; var n = square.length, i, j, k, m, seen = new Array(n); for (i=0; i k || 0 < seen[k]) return false; seen[k] = 1; } // columns for (k=0; k k || 0 < seen[k]) return false; seen[k] = 1; } } return true; } function find(a, b, nested) { if (nested) { if (!a || !a.length) return -1; var index, found, i, j, k, n = a.length, m = b.length; for (i=0; i=b; } ,lte: function(a, b) { return a<=b; } ,gt: function(a, b) { return a>b; } ,lt: function(a, b) { return a= m) && (a <= M) : (a > m) && (a < M); } ,clamp: function(a, m, M) { return a < m ? m : (a > M ? M : a); } ,wrap: function(a, m, M) { return a < m ? M : (a > M ? m : a); } ,wrapR: function(a, M) { return a < 0 ? a+M : a; } ,add: addn ,sub: function(a, b){ return a-b; } ,mul: muln ,div: function(a, b){ return stdMath.floor(a/b); } ,divceil: function(a, b){ return stdMath.ceil(a/b); } ,mod: function(a, b){ return a % b; } ,pow: stdMath.pow ,shl: function(a, b){ return a << b; } ,shr: function(a, b){ return a >> b; } ,bor: function(a, b){ return a | b; } ,band: function(a, b){ return a & b; } ,xor: function(a, b){ return a ^ b; } ,abs: stdMath.abs ,min: stdMath.min ,max: stdMath.max ,rnd: rndInt }; // pluggable arithmetics, eg biginteger Arithmetic Abacus.Arithmetic = Merge({}, DefaultArithmetic, { isDefault: function(){return (0 === this.O) && (this.add === addn);} ,neg: function(a){return Abacus.Arithmetic.mul(Abacus.Arithmetic.J, a);} ,abs: function(a){return Abacus.Arithmetic.gt(Abacus.Arithmetic.O, a) ? Abacus.Arithmetic.neg(a) : a;} ,min: function(a, b){return Abacus.Arithmetic.lt(a, b) ? a : b;} ,max: function(a, b){return Abacus.Arithmetic.gt(a, b) ? a : b;} ,divceil: function(a, b){ if (null == b) return a; // https://stackoverflow.com/questions/921180/how-can-i-ensure-that-a-division-of-integers-is-always-rounded-up var Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, I = Arithmetic.I, roundedTowardsZeroQuotient, dividedEvenly, wasRoundedDown; roundedTowardsZeroQuotient = Arithmetic.div(a, b); dividedEvenly = Arithmetic.equ(O, Arithmetic.mod(a, b)); if (dividedEvenly) return roundedTowardsZeroQuotient; wasRoundedDown = (Arithmetic.gt(a, O) === Arithmetic.gt(b, O)); return wasRoundedDown ? Arithmetic.add(roundedTowardsZeroQuotient, I) : roundedTowardsZeroQuotient; } }); // math / num theory utilities Abacus.Math = { rnd: stdMath.random ,rndInt: rndInt ,factorial: factorial ,stirling: stirling ,partitions: partitions ,compositions: compositions ,bell: bell ,catalan: catalan ,fibonacci: fibonacci ,polygonal: polygonal ,sum_nk: sum_nk ,sum: sum ,product: product ,pow2: pow2 ,exp: exp ,powsq: function(b, e) { var Arithmetic = Abacus.Arithmetic; e = is_instance(e, Integer) ? e.num : Arithmetic.num(e); if (is_instance(b, Integer)) return new b[CLASS](powsq(b.num, e)); return powsq(Arithmetic.num(b), e); } ,addm: function(a, b, m) { var Arithmetic = Abacus.Arithmetic; m = is_instance(m, Integer) ? m.num : Arithmetic.num(m); b = is_instance(b, Integer) ? b.num : Arithmetic.num(b); if (is_instance(a, Integer)) return new a[CLASS](addm(a.num, b, m)); return addm(Arithmetic.num(a), b, m); } ,negm: function(a, m) { var Arithmetic = Abacus.Arithmetic; m = is_instance(m, Integer) ? m.num : Arithmetic.num(m); if (is_instance(a, Integer)) return new a[CLASS](negm(a.num, m)); return negm(Arithmetic.num(a), m); } ,mulm: function(a, b, m) { var Arithmetic = Abacus.Arithmetic; m = is_instance(m, Integer) ? m.num : Arithmetic.num(m); b = is_instance(b, Integer) ? b.num : Arithmetic.num(b); if (is_instance(a, Integer)) return new a[CLASS](mulm(a.num, b, m)); return mulm(Arithmetic.num(a), b, m); } ,invm: function(a, m) { var Arithmetic = Abacus.Arithmetic; m = is_instance(m, Integer) ? m.num : Arithmetic.num(m); if (is_instance(a, Integer)) return new a[CLASS](invm(a.num, m)); return invm(Arithmetic.num(a), m); } ,powm: function(a, b, m) { var Arithmetic = Abacus.Arithmetic; m = is_instance(m, Integer) ? m.num : Arithmetic.num(m); b = is_instance(b, Integer) ? b.num : Arithmetic.num(b); if (is_instance(a, Integer)) return new a[CLASS](powm(a.num, b, m)); return powm(Arithmetic.num(a), b, m); } ,isqrt: function(a) { var Arithmetic = Abacus.Arithmetic; if (is_instance(a, Integer)) return new a[CLASS](isqrt(a.num)); return isqrt(Arithmetic.num(a)); } ,ikthroot: function(a, k) { var Arithmetic = Abacus.Arithmetic; k = is_instance(k, Integer) ? k.num : Arithmetic.num(k); if (is_instance(a, Integer)) return new a[CLASS](ikthroot(a.num, k)); return ikthroot(Arithmetic.num(a), k); } ,isqrtp: function(a, p) { var Arithmetic = Abacus.Arithmetic; p = is_instance(p, Integer) ? p.num : Arithmetic.num(p); if (is_instance(a, Integer)) return new a[CLASS](isqrtp(a.num, p)); return isqrtp(Arithmetic.num(a), p); } ,ilog: function(x, b) { var Arithmetic = Abacus.Arithmetic; b = is_instance(b, Integer) ? b.num : Arithmetic.num(b); if (is_instance(x, Integer)) return new x[CLASS](ilog(x.num, b)); return ilog(Arithmetic.num(x), b); } ,divisors: function(n, as_generator) { var Arithmetic = Abacus.Arithmetic; return divisors(is_instance(n, Integer) ? n : Arithmetic.num(n), true===as_generator); } ,legendre: function(a, p) { var Arithmetic = Abacus.Arithmetic; p = is_instance(p, Integer) ? p.num : Arithmetic.num(p); if (is_instance(a, Integer)) return new a[CLASS](legendre_symbol(a.num, p)); return legendre_symbol(Arithmetic.num(a), p); } ,jacobi: function(a, n) { var Arithmetic = Abacus.Arithmetic; n = is_instance(n, Integer) ? n.num : Arithmetic.num(n); if (is_instance(a, Integer)) return new a[CLASS](jacobi_symbol(a.num, n)); return jacobi_symbol(Arithmetic.num(a), n); } ,moebius: function(n) { var Arithmetic = Abacus.Arithmetic; if (is_instance(n, Integer)) return new n[CLASS](moebius(n.num)); return moebius(Arithmetic.num(n)); } ,pollardRho: function(n, s, a, retries, max_steps, F) { var N = Abacus.Arithmetic.num, f; if (null != a) a = is_instance(a, Integer) ? a.num : N(a); if (null != s) s = is_instance(s, Integer) ? s.num : N(s); if (is_instance(n, Integer)) { f = pollard_rho(n.num, s, a, retries, max_steps||null, F||null); return null==f ? f : new n[CLASS](f); } return pollard_rho(N(n), s, a, retries, max_steps||null, F||null); } ,factorize: function(n) { var Arithmetic = Abacus.Arithmetic; return factorize(is_instance(n, Integer) ? n : Arithmetic.num(n)); } ,isProbablePrime: function(n) { var Arithmetic = Abacus.Arithmetic; return is_probable_prime(is_instance(n, Integer) ? n.num : Arithmetic.num(n)); } ,isPrime: function(n) { var Arithmetic = Abacus.Arithmetic; return is_prime(is_instance(n, Integer) ? n.num : Arithmetic.num(n)); } ,nextPrime: function(n, dir) { var Arithmetic = Abacus.Arithmetic; return next_prime(is_instance(n, Integer) ? n.num : Arithmetic.num(n), -1===dir?-1:1); } ,gcd: function(/* args */) { var Arithmetic = Abacus.Arithmetic, args = slice.call(arguments.length && (is_array(arguments[0])||is_args(arguments[0])) ? arguments[0] : arguments), res, INT = null; res = gcd(args.map(function(a){ if (is_instance(a, Integer)) { if (!INT) INT = a[CLASS]; return a.num; } return Arithmetic.num(a); })); return INT ? new INT(res) : res; } ,xgcd: function(/* args */) { var Arithmetic = Abacus.Arithmetic, args = slice.call(arguments.length && (is_array(arguments[0])||is_args(arguments[0])) ? arguments[0] : arguments), res, INT = null; res = xgcd(args.map(function(a){ if (is_instance(a, Integer)) { if (!INT) INT = a[CLASS]; return a.num; } return Arithmetic.num(a); })); return INT && res ? res.map(function(g){return new INT(g);}) : res; } ,lcm: function(/* args */) { var Arithmetic = Abacus.Arithmetic, args = slice.call(arguments.length && (is_array(arguments[0])||is_args(arguments[0])) ? arguments[0] : arguments), res, INT = null; res = lcm(args.map(function(a){ if (is_instance(a, Integer)) { if (!INT) INT = a[CLASS]; return a.num; } return Arithmetic.num(a); })); return INT ? new INT(res) : res; } ,diophantine: function(a, b, with_param, with_free_vars) { var Arithmetic = Abacus.Arithmetic; if ((!is_array(a) && !is_args(a)) || !a.length) return null; return solvedioph(Arithmetic.nums(a), Arithmetic.num(b||0), with_param, true===with_free_vars); } ,diophantines: function(a, b, with_param, with_free_vars) { var ring = Ring.Z(); if (!is_instance(a, Matrix) && !is_array(a) && !is_args(a)) return null; if (is_instance(a, Matrix) && (!a.nr || !a.nc)) return null; if (!is_instance(a, Matrix) && !a.length) return null; //a = is_instance(a, Matrix) ? a : a; if (!is_instance(b, Matrix) && !is_array(b) && !is_args(b)) b = array(is_instance(a, Matrix) ? a.nr : a.length, function(){return b||0;}); b = is_instance(b, Matrix) ? b : ring.cast(b); return solvediophs(a, b, with_param, true===with_free_vars); } ,congruence: function(a, b, m, with_param, with_free_vars) { var Arithmetic = Abacus.Arithmetic; if ((!is_array(a) && !is_args(a)) || !a.length) return null; return solvecongr(Arithmetic.nums(a), Arithmetic.num(b||0), Arithmetic.num(m||0), with_param, true===with_free_vars); } ,congruences: function(a, b, m, with_param, with_free_vars) { var ring = Ring.Z(); if (!is_instance(a, Matrix) && !is_array(a) && !is_args(a)) return null; if (is_instance(a, Matrix) && (!a.nr || !a.nc)) return null; if (!is_instance(a, Matrix) && !a.length) return null; a = is_instance(a, Matrix) ? a : ring.cast(a); if (!is_instance(b, Matrix) && !is_array(b) && !is_args(b)) b = array(is_instance(a, Matrix) ? a.nr : a.length, function(){return b||0;}); b = is_instance(b, Matrix) ? b : ring.cast(b); if (!is_instance(m, Matrix) && !is_array(m) && !is_args(m)) m = array(is_instance(a, Matrix) ? a.nr : a.length, function(){return m||0;}); m = is_instance(m, Matrix) ? m : ring.cast(m); return solvecongrs(a, b, m, with_param, true===with_free_vars); } ,pythagorean: function(a, with_param) { var Arithmetic = Abacus.Arithmetic; if ((!is_array(a) && !is_args(a)) || !a.length) return null; return solvepythag(Arithmetic.nums(a), with_param) } ,linears: function(a, b, with_param) { var ring = Ring.Q(); if (!is_instance(a, Matrix) && !is_array(a) && !is_args(a)) return null; if (is_instance(a, Matrix) && (!a.nr || !a.nc)) return null; if (!is_instance(a, Matrix) && !a.length) return null; //a = is_instance(a, Matrix) ? a : a; if (!is_instance(b, Matrix) && !is_array(b) && !is_args(b)) b = array(is_instance(a, Matrix) ? a.nr : a.length, function(){return b||0;}); b = is_instance(b, Matrix) ? b : ring.cast(b); return solvelinears(a, b, with_param); } ,lineqs: function(a, b, param) { var ring = Ring.Q(); if (!is_instance(a, Matrix) && !is_array(a) && !is_args(a)) return null; if (is_instance(a, Matrix) && (!a.nr || !a.nc)) return null; if (!is_instance(a, Matrix) && !a.length) return null; //a = is_instance(a, Matrix) ? a : a; if (!is_instance(b, Matrix) && !is_array(b) && !is_args(b)) b = array(is_instance(a, Matrix) ? a.nr : a.length, function(){return b||0;}); b = is_instance(b, Matrix) ? b : ring.cast(b); return solvelineqs(a, b, param); } ,groebner: buchberger_groebner ,dotp: function(a, b) { var Arithmetic = Abacus.Arithmetic; return (is_array(a)||is_args(a)) && (is_array(b)||is_args(b)) ? dotp(a, b, Arithmetic) : Arithmetic.O; } ,orthogonalize: function(v) { return (is_array(v)||is_args(v)) && v.length ? gramschmidt(v) : []; } }; // array/list utilities Abacus.Util = { array: array ,operate: operate ,unique: unique ,intersection: intersection ,difference: difference ,multi_difference: multi_difference ,union: merge ,bsearch: binarysearch ,bisect: bisect ,complementation: complementation ,reflection: reflection ,reversion: reversion ,lcs: lcs ,gray: gray ,igray: igray ,grayn: grayn ,igrayn: igrayn ,finitedifference: fdiff ,partialsum: psum ,convolution: convolution ,summation: summation ,wheel: wheel ,sort: mergesort ,shuffle: shuffle ,pick: pick ,pluck: pluck ,is_mirror_image: is_mirror_image ,cycle_detection: floyd_cycle_detection }; // Abacus.BitArray, Packed Bit Array Implementation Abacus.BitArray = Class({ constructor: function BitArray(n) { var self = this; if (!is_instance(self, BitArray)) return new BitArray(n); self.length = n; self.bits = new Uint32Array(stdMath.ceil(n/32)); } ,length: 0 ,bits: null ,dispose: function() { var self = this; self.length = null; self.bits = null; return self; } ,clone: function() { var self = this, c = new Abacus.BitArray(self.length); c.bits = new Uint32Array(self.bits); return c; } ,fromArray: function(b) { var self = this; self.bits = new Uint32Array(b); return self; } ,toArray: function() { return slice.call(this.bits); } ,toString: function() { return this.toArray().map(to_fixed_binary_string_32).join(''); } ,reset: function() { var self = this, bits = self.bits, len = bits.length, i; for (i=0; i>>5] & (1<<(bit&31))); } ,set: function(bit) { var self = this; self.bits[bit>>>5] |= 1<<(bit&31); return self; } ,unset: function(bit) { var self = this; self.bits[bit>>>5] &= ~(1<<(bit&31)); return self; } ,toggle: function(bit) { var self = this; self.bits[bit>>>5] ^= 1<<(bit&31); return self; } }); // ListSet, a fixed-size array which is also a doubly-lnked list and allows for O(1) retrieval, removal, re-addition and traverse asc/desc only valid items. ListSet = Abacus.ListSet = function ListSet(a) { var self = this, i, n, _first, _last; if (!is_instance(self, ListSet)) return new ListSet(a); a = is_array(a) ? a.slice() : new Array(+a); n = a.length; for (i=0; ix || x>=n) return self; item = a[x]; } else if (x && (null != x.index)) { if (0>x.index || x.index>=n) return self; item = x; } else { return self; } if (item.incl) { if (_first === item) _first = item.next; if (_last === item) _last = item.prev; if (item.prev) item.prev.next = item.next; if (item.next) item.next.prev = item.prev; item.incl = false; } return self; }; self.add = function(x) { // add x back to listset var item = null; if (x === +x) { if (0>x || x>=n) return self; item = a[x]; } else if (x && (null != x.index)) { if (0>x.index || x.index>=n) return self; item = x; } else { return self; } if (!item.incl) { if (_first === item.next) _first = item; if (_last === item.prev) _last = item; if (item.prev) item.prev.next = item; if (item.next) item.next.prev = item; item.incl = true; } return self; }; self.has = function(x) { // check if x is included var item = null; if (x === +x) { if (0>x || x>=n) return false; item = a[x]; } else if (x && (null != x.index)) { if (0>x.index || x.index>=n) return false; item = x; } else { return false; } return item.incl; }; self.item = function(x) { // return x var item = null; if (x === +x) { if (0>x || x>=n) return false; item = a[x]; } else if (x && (null != x.index)) { if (0>x.index || x.index>=n) return false; item = x; } else { return null; } return item; }; self.dispose = function() { a = null; _first = null; _last = null; return self; }; }; // auxiliary data structure to count certain things in log(n) time // https://cs.stackexchange.com/questions/142186/faster-algorithm-for-specific-inversion-count-part-2 function Counters(n) { var self = this, k, C; if (!is_instance(self, Counters)) return new Counters(n); k = stdMath.ceil(log2(n)); C = array((1 << (k+1)), function(i){ //var kk = 0; //while (kk <= k && !(i & 1)) {kk++; i >>>= 1;} return array(k+1, 0, 0); }); self.offset = function(i, delta) { if (0 > i) return self; i++; var x = 0, y, j, il, ih, yl, yh; //il = (i >>> 0) & 0xFFFF; //ih = (i >>> 16) & 0xFFFF; for (j=k; (0<=j) && (0>> 0) & 0xFFFF; //yh = (y >>> 16) & 0xFFFF; if ((i & y) /*|| (ih & yh)*/) { C[x][j] += delta; x += y; i &= ~y; //ih &= ~yh; } } return self; }; self.eval = function(i) { var r = 0, j, y, il, ih, yl, yh; //ih = (i >>> 16) & 0xFFFF; //il = (i >>> 0) & 0xFFFF; for (j=0; j<=k; j++) { y = (1 << j); //yh = (y >>> 16) & 0xFFFF; //yl = (y >>> 0) & 0xFFFF; if ((i & y) /*|| (ih & yh)*/) { i &= ~y; //ih &= ~yh; } else { r += C[i/*((ih << 16) | (il)) & 0xFFFFFFFF*/][j]; } } return r; }; self.dispose = function() { C = null; return self; }; } // Abacus.Node, Node class which can represent (dynamic) Linked Lists, Binary Trees and similar structures Node = Abacus.Node = function Node(value, left, right, top) { var self = this; if (!is_instance(self, Node)) return new Node(value, left, right, top); self.v = value; self.l = left || null; self.r = right || null; self.t = top || null; self.dispose = function() { self.v = null; self.l = null; self.r = null; self.t = null; return self; }; }; // min/max Heap / priority queue class, adapted from python's heapq.py Heap = Abacus.Heap = Class({ constructor: function Heap(h, type, cmp) { var self = this; if (!is_instance(self, Heap)) return new Heap(h, type, cmp); type = String(type||"min").toLowerCase().slice(0, 3); self.type = "max" === type ? "max" : "min"; if (!is_callable(cmp)) cmp = Heap.CMP; self.cmp = cmp; h = h || []; self._h = Heap.heapify(h, self.type, self.cmp); } ,__static__: { CMP: function(a, b) { return ab ? 1 : 0); } ,heapify: function(x, type, cmp) { // Transform list into a heap/maxheap, in-place, in O(len(x)) time. var n = x.length, i; // Transform bottom-up. The largest index there's any point to looking at // is the largest with a child index in-range, so must have 2*i + 1 < n, // or i < (n-1)/2. If n is even = 2*j, this is (2*j-1)/2 = j-1/2 so // j-1 is the largest, which is n//2 - 1. If n is odd = 2*j+1, this is // (2*j+1-1)/2 = j so j-1 is the largest, and that's again n//2-1. cmp = cmp || Heap.CMP; if ("max" === type) { for (i=(n>>>1)-1; i>=0; i--) Heap._siftup_max(x, i, cmp); } else { for (i=(n>>>1)-1; i>=0; i--) Heap._siftup(x, i, cmp); } return x; } ,_siftdown: function(heap, startpos, pos, cmp) { var newitem = heap[pos], parentpos, parent; // Follow the path to the root, moving parents down until finding a place // newitem fits. while (pos > startpos) { parentpos = (pos - 1) >>> 1; parent = heap[parentpos]; if (0 > cmp(newitem, parent)) { heap[pos] = parent; pos = parentpos; continue; } break; } heap[pos] = newitem; } ,_siftup: function(heap, pos, cmp) { var endpos = heap.length, startpos = pos, newitem = heap[pos], childpos, rightpos; // Bubble up the smaller child until hitting a leaf. childpos = 2*pos + 1; // leftmost child position while (childpos < endpos) { // Set childpos to index of smaller child. rightpos = childpos + 1; if (rightpos startpos) { parentpos = (pos - 1) >>> 1; parent = heap[parentpos]; if (0>cmp(parent, newitem)) { heap[pos] = parent; pos = parentpos; continue; } break; } heap[pos] = newitem; } ,_siftup_max: function(heap, pos, cmp) { // Maxheap variant of _siftup var endpos = heap.length, startpos = pos, newitem = heap[pos], childpos, rightpos; // Bubble up the larger child until hitting a leaf. childpos = 2*pos + 1; // leftmost child position while (childpos < endpos) { // Set childpos to index of larger child. rightpos = childpos + 1; if (rightpos heap[0]: item = heapreplace(heap, item) */ returnitem = self.peek(); self._h[0] = item; // Maxheap version of a heappop followed by a heappush. if ("max" === self.type) Heap._siftup_max(self._h, 0, self.cmp); else Heap._siftup(self._h, 0, self.cmp); return returnitem; } }); function nmax(/* args */) { var args = arguments.length && (is_array(arguments[0]) || is_args(arguments[0])) ? arguments[0] : arguments; return args.length ? operate(function(max, a){ return a.gt(max) ? a : max; }, args[0], 1, args.length-1) : null; } function nmin(/* args */) { var args = arguments.length && (is_array(arguments[0]) || is_args(arguments[0])) ? arguments[0] : arguments; return args.length ? operate(function(min, a){ return a.lt(min) ? a : min; }, args[0], 1, args.length-1) : null; } function typecast(ClassTypeCheck, toClassType) { var ClassType = null; if (is_array(ClassTypeCheck) && is_callable(ClassTypeCheck[0])) { ClassType = ClassTypeCheck[0]; ClassTypeCheck = function(a){return is_instance(a, ClassType);}; toClassType = is_callable(toClassType) ? toClassType : function(a){return new ClassType(a);}; } else if (!is_callable(ClassTypeCheck)) { ClassTypeCheck = function(a){return true;}; toClassType = function(a){return a;}; } return function type_cast(a) { if (is_array(a) || is_args(a)) { for (var i=0,l=a.length; i a); else if (is_instance(a, INumber)) return a.lt(this); return false; } ,gte: function(a) { if (is_number(a)) return (this >= a); else if (is_instance(a, INumber)) return a.lte(this); return false; } ,lt: function(a) { if (is_number(a)) return (this < a); else if (is_instance(a, INumber)) return a.gt(this); return false; } ,lte: function(a) { if (is_number(a)) return (this <= a); else if (is_instance(a, INumber)) return a.gte(this); return false; } ,real: function() { return this; } ,imag: function() { return 0; } ,abs: function() { return stdMath.abs(this); } ,neg: function() { return -this; } ,conj: function() { return this; } ,inv: NotImplemented ,add: function(a) { return is_instance(a, INumber) ? a.add(this) : (this + a); } ,sub: function(a) { return is_instance(a, INumber) ? a.neg().add(this) : (this - a); } ,mul: function(a) { return is_instance(a, INumber) ? a.mul(this) : (this * a); } ,div: function(a) { if (is_instance(a, Numeric)) return a[CLASS](this).div(a); return is_instance(a, INumber) ? null : stdMath.floor(this / a); } ,mod: function(a) { if (is_instance(a, Numeric)) return a[CLASS](this).mod(a); return is_instance(a, INumber) ? null : (this % a); } ,divmod: function(a) { return [this.div(a), this.mod(a)]; } ,divides: function(a) { if (0 === this) return false; if (is_number(a)) return (0 === (a % this)); else if (is_instance(a, Integer)) return a.mod(this).equ(0); else if (is_instance(a, Numeric)) return true; return false; } ,pow: function(n) { return stdMath.pow(this, +n); } ,rad: function(n) { return jskthroot(this, n); } }; INumber = Class(Merge({ constructor: function INumber() { } ,dispose: function() { return this; } ,clone: function() { return 0 + this; } ,valueOf: function() { return 0; } ,toString: function() { return ''; } ,toTex: function() { return this.toString(); } }, INUMBER)); // Numeric is INumber that represents strictly constant numbers, eg Integer, Rational, Complex Numeric = Class(INumber, { constructor: function Numeric() { } ,clone: function() { return new this[CLASS](this); } ,isConst: function() { return true; } ,isInt: function() { return false; } ,real: function() { return this; } ,imag: function() { return this[CLASS].Zero(); } }); // Symbolic is INumber that represents generally non-constant symbolic objects, eg Expr, Polynomial, MultiPolynomial, RationalFunc Symbolic = Class(INumber, { constructor: function Symbolic() { } ,clone: function() { return new this[CLASS](this); } ,isConst: function() { return false; } ,isInt: function() { return false; } ,c: function() { return 0; } ,valueOf: function() { return this.c().valueOf(); } ,gt: NotImplemented ,gte: NotImplemented ,lt: NotImplemented ,lte: NotImplemented ,real: function() { return this; } ,imag: function() { return this[CLASS].Zero(); } ,abs: NotImplemented ,neg: NotImplemented ,conj: NotImplemented ,inv: NotImplemented ,add: NotImplemented ,sub: NotImplemented ,mul: NotImplemented ,div: NotImplemented ,mod: NotImplemented ,divmod: NotImplemented ,pow: NotImplemented ,rad: NotImplemented ,d: NotImplemented ,evaluate: NotImplemented }); // Poly is represents a polynomial either univariate or multivariate eg Polynomial, MultiPolynomial Poly = Class(Symbolic, { constructor: function Poly() { } }); // Abacus.Integer, represents an integer Integer = Abacus.Integer = Class(Numeric, { constructor: function Integer(num) { var self = this, Arithmetic = Abacus.Arithmetic; if (!is_instance(self, Integer)) return new Integer(num); if (is_instance(num, Symbolic)) num = num.c(); if (is_instance(num, Complex)) num = num.real(); if (is_instance(num, Rational)) num = num.integer(true); if (is_instance(num, Integer)) self._isp = num._isp; if (is_instance(num, [Integer, IntegerMod])) num = num.num; self.num = Arithmetic.num(num||0); } ,__static__: { O: null ,I: null ,J: null ,Zero: function() { if (null == Integer.O) Integer.O = Integer(Abacus.Arithmetic.O); return Integer.O; } ,One: function() { if (null == Integer.I) Integer.I = Integer(Abacus.Arithmetic.I); return Integer.I; } ,MinusOne: function() { if (null == Integer.J) Integer.J = Integer(Abacus.Arithmetic.J); return Integer.J; } ,hasInverse: function() { return false; } ,cast: null // added below ,gcd: igcd ,xgcd: ixgcd ,lcm: ilcm ,max: nmax ,min: nmin ,rnd: function(m, M) { var Arithmetic = Abacus.Arithmetic, t; m = Integer.cast(m); M = Integer.cast(M); if (M.lt(m)) { t=m; m=M; M=t; } return m.equ(M) ? m : Integer(Arithmetic.rnd(m.num, M.num)); } ,fromString: function(s) { s = trim(String(s)); if (!s.length) return Integer.Zero(); if ('+' === s.charAt(0)) s = trim(s.slice(1)); if ((-1 !== s.indexOf('e')) || (-1 !== s.indexOf('.'))) return Integer(Rational.fromString(s)); return s.length ? Integer(Abacus.Arithmetic.num(s)) : Integer.Zero(); } } ,num: null ,_n: null ,_isp: null ,_str: null ,dispose: function() { var self = this; if (self._n && self===self._n._n) { self._n._n = null; } self.num = null; self._n = null; self._str = null; return self; } ,isInt: function() { return true; } ,isPrime: function() { var self = this, Arithmetic = Abacus.Arithmetic; if (null == self._isp) self._isp = is_probable_prime(Arithmetic.abs(self.num)) && is_prime(Arithmetic.abs(self.num)); return self._isp; } ,equ: function(a) { var self = this, Arithmetic = Abacus.Arithmetic; if (is_instance(a, [Integer, IntegerMod])) return Arithmetic.equ(self.num, a.num); else if (is_instance(a, INumber)) return a.equ(self.num); else if (Arithmetic.isNumber(a)) return Arithmetic.equ(self.num, a); else if (is_string(a)) return a === self.toString(); return false; } ,gt: function(a) { var self = this, Arithmetic = Abacus.Arithmetic; if (is_instance(a, [Integer, IntegerMod])) return Arithmetic.gt(self.num, a.num); else if (is_instance(a, INumber)) return a.lt(self.num); else if (Arithmetic.isNumber(a)) return Arithmetic.gt(self.num, a); return false; } ,gte: function(a) { var self = this, Arithmetic = Abacus.Arithmetic; if (is_instance(a, [Integer, IntegerMod])) return Arithmetic.gte(self.num, a.num); else if (is_instance(a, INumber)) return a.lte(self.num); else if (Arithmetic.isNumber(a)) return Arithmetic.gte(self.num, a); return false; } ,lt: function(a) { var self = this, Arithmetic = Abacus.Arithmetic; if (is_instance(a, [Integer, IntegerMod])) return Arithmetic.lt(self.num, a.num); else if (is_instance(a, INumber)) return a.gt(self.num); else if (Arithmetic.isNumber(a)) return Arithmetic.lt(self.num, a); return false; } ,lte: function(a) { var self = this, Arithmetic = Abacus.Arithmetic; if (is_instance(a, [Integer, IntegerMod])) return Arithmetic.lte(self.num, a.num); else if (is_instance(a, INumber)) return a.gte(self.num); else if (Arithmetic.isNumber(a)) return Arithmetic.lte(self.num, a); return false; } ,abs: function() { return Integer(Abacus.Arithmetic.abs(this.num)); } ,neg: function() { var self = this; if (null == self._n) { self._n = Integer(Abacus.Arithmetic.neg(self.num)); self._n._n = self; } return self._n; } ,inv: NotImplemented ,add: function(a) { var self = this, Arithmetic = Abacus.Arithmetic; if (is_instance(a, [Integer, IntegerMod])) return Integer(Arithmetic.add(self.num, a.num)); else if (is_instance(a, INumber)) return a.add(self.num); else if (Arithmetic.isNumber(a)) return Integer(Arithmetic.add(self.num, a)); return self; } ,sub: function(a) { var self = this, Arithmetic = Abacus.Arithmetic; if (is_instance(a, [Integer, IntegerMod])) return Integer(Arithmetic.sub(self.num, a.num)); else if (is_instance(a, INumber)) return a.neg().add(self.num); else if (Arithmetic.isNumber(a)) return Integer(Arithmetic.sub(self.num, a)); return self; } ,mul: function(a) { var self = this, Arithmetic = Abacus.Arithmetic; if (is_instance(a, [Integer, IntegerMod])) return Integer(Arithmetic.mul(self.num, a.num)); else if (is_instance(a, INumber)) return a.mul(self.num); else if (Arithmetic.isNumber(a)) return Integer(Arithmetic.mul(self.num, a)); return self; } ,div: function(a) { var self = this, Arithmetic = Abacus.Arithmetic; if (is_instance(a, [Integer, IntegerMod])) return Integer(Arithmetic.div(self.num, a.num)); else if (is_instance(a, Complex)) return Complex(self).div(a); else if (is_instance(a, Rational)) return Rational(self).div(a); else if (Arithmetic.isNumber(a)) return Integer(Arithmetic.div(self.num, a)); return self; } ,mod: function(a) { var self = this, Arithmetic = Abacus.Arithmetic; if (is_instance(a, [Integer, IntegerMod])) return Integer(Arithmetic.mod(self.num, a.num)); else if (is_instance(a, Complex)) return Complex(self).mod(a); else if (is_instance(a, Rational)) return Rational(self).mod(a); else if (Arithmetic.isNumber(a)) return Integer(Arithmetic.mod(self.num, a)); return self; } ,divmod: function(a) { var self = this; return [self.div(a), self.mod(a)]; } ,divides: function(a) { var self = this, Arithmetic = Abacus.Arithmetic, O = Arithmetic.O; if (Arithmetic.equ(O, self.num)) return false; if (is_instance(a, Integer)) return Arithmetic.equ(O, Arithmetic.mod(a.num, self.num)); else if (is_instance(a, INumber)) return true; else if (Arithmetic.isNumber(a)) return Arithmetic.equ(O, Arithmetic.mod(Arithmetic.num(a), self.num)); return false; } ,integer: function(raw) { var self = this; return true===raw ? self.num : self; } ,pow: function(n) { var self = this, Arithmetic = Abacus.Arithmetic; n = Integer.cast(n); if (n.lt(Arithmetic.O)) return null; // not supported else if (n.equ(Arithmetic.I)) return self; return Integer(Arithmetic.pow(self.num, n.num)); } ,rad: function(n) { var self = this, Arithmetic = Abacus.Arithmetic; n = Integer.cast(n); if (n.lt(Arithmetic.I)) return null; // not supported else if (n.equ(Arithmetic.I)) return self; return Integer(ikthroot(self.num, n.num)); } ,valueOf: function() { return Abacus.Arithmetic.val(this.num); } ,toString: function() { var self = this; if (null == self._str) self._str = String(self.num); return self._str; } ,toDec: function(precision) { var dec = this.toString(); if (is_number(precision) && 0 precision) { digit = dec.charAt(point+1+precision); d = parseInt(digit, 10); dec = dec.slice(0, point+1+precision).split(''); i = dec.length-1; i0 = '-'===dec[0] ? 1 : 0; carry = (d >= 5); if (point === i) i--; while (carry && (i >= i0)) { d = parseInt(dec[i], 10); carry = (9 === d); dec[i] = String(carry ? 0 : d+1); i--; if (point === i) i--; } if (carry) dec.splice(i0, 0, '1'); if ('.' === dec[dec.length-1]) dec.pop(); dec = dec.join(''); } return dec; } else { return self._dec; } } ,valueOf: function() { var Arithmetic = Abacus.Arithmetic; return Arithmetic.val(this.num)/Arithmetic.val(this.den); } ,toString: function(parenthesized) { var self = this, Arithmetic = Abacus.Arithmetic; if (null == self._str) { self._str = String(self.num) + (Arithmetic.equ(Arithmetic.I, self.den) ? '' : ('/'+String(self.den))); self._strp = Arithmetic.equ(Arithmetic.I, self.den) ? String(self.num) : ((Arithmetic.gt(Arithmetic.O, self.num) ? '-' : '')+'('+String(Arithmetic.abs(self.num))+'/'+String(self.den)+')'); } return parenthesized ? self._strp : self._str; } ,toTex: function() { var self = this, Arithmetic = Abacus.Arithmetic; if (null == self._tex) self._tex = Arithmetic.equ(Arithmetic.I, self.den) ? Tex(self.num) : ((Arithmetic.gt(Arithmetic.O, self.num) ? '-' : '')+'\\frac{'+Tex(Arithmetic.abs(self.num))+'}{'+Tex(self.den)+'}'); return self._tex; } }); Rational.cast = typecast([Rational], function(a){ return is_string(a) ? Rational.fromString(a) : new Rational(a); }); // Abacus.Complex represents a complex number with Rational parts Complex = Abacus.Complex = Class(Numeric, { constructor: function Complex(/*real, imag*/) { var self = this, args = arguments, real, imag; if (args.length && (is_array(args[0]) || is_args(args[0]))) args = args[0]; if (1 < args.length) { real = args[0]; imag = args[1]; } else if (1 === args.length) { real = args[0]; imag = Rational.Zero(); } else { real = Rational.Zero(); imag = Rational.Zero(); } if (is_instance(real, Symbolic)) real = real.c(); if (is_instance(imag, Symbolic)) imag = imag.c(); if (is_instance(real, Complex)) { imag = real.imag(); real = real.real(); } if (!is_instance(self, Complex)) return new Complex(real, imag); self.re = Rational.cast(real); self.im = Rational.cast(imag); } ,__static__: { Symbol: 'i' ,O: null ,I: null ,J: null ,i: null ,j: null ,Zero: function() { if (null == Complex.O) Complex.O = Complex(Rational.Zero(), Rational.Zero()); return Complex.O; } ,One: function() { if (null == Complex.I) Complex.I = Complex(Rational.One(), Rational.Zero()); return Complex.I; } ,MinusOne: function() { if (null == Complex.J) Complex.J = Complex(Rational.MinusOne(), Rational.Zero()); return Complex.J; } ,Img: function() { if (null == Complex.i) Complex.i = Complex(Rational.Zero(), Rational.One()); return Complex.i; } ,MinusImg: function() { if (null == Complex.j) Complex.j = Complex(Rational.Zero(), Rational.MinusOne()); return Complex.j; } ,hasInverse: function() { return true; } ,cast: null // added below ,gcd: cgcd ,xgcd: cxgcd ,lcm: clcm ,max: nmax ,min: nmin ,rnd: function(m, M, limit) { m = Complex.cast(m); M = Complex.cast(M); return Complex(Rational.rnd(m.real(), M.real(), limit), Rational.rnd(m.imag(), M.imag(), limit)); } ,fromString: function(s) { var m, signre, signim, real, imag, O = Complex.Zero(), pattern = /^\(?(?:([\+\-])?\s*\(?((?:\\frac\{-?\d+\}\{-?\d+\})|(?:-?\d+(?:\.\d*(?:\[\d+\])?)?(?:e-?\d+)?(?:\/-?\d+)?))?\)?(\*?[ij])?)(?:\s*([\+\-])?\s*(?:\(?((?:\\frac\{-?\d+\}\{-?\d+\})|(?:-?\d+(?:\.\d*(?:\[\d+\])?)?(?:e-?\d+)?(?:\/-?\d+)?))\)?\*?)?([ij]))?\)?$/; s = trim(String(s)); if (!s.length) return O; m = s.match(pattern); if (!m) return O; if (m[3] && !m[6]) { // given in opposite order or imaginary only imag = m[2] ? m[2] : (m[3] ? '1' : '0'); real = m[5] || '0'; signim = '-'===m[1] ? '-' : ''; signre = '-'===m[4] ? '-' : ''; } else { // given in correct order or real only imag = m[5] ? m[5] : (m[6] ? '1' : '0'); real = m[2] || '0'; signim = '-'===m[4] ? '-' : ''; signre = '-'===m[1] ? '-' : ''; } return Complex(Rational.fromString(signre+real), Rational.fromString(signim+imag)); } } ,re: null ,im: null ,_n: null ,_i: null ,_c: null ,_str: null ,_strp: null ,_tex: null ,_dec: null ,_norm: null ,_int: null ,_rem: null ,_simpl: false ,dispose: function() { var self = this; if (self._n && self===self._n._n) { self._n._n = null; } if (self._i && self===self._i._i) { self._i._i = null; } if (self._c && self===self._c._c) { self._c._c = null; } self.re = null; self.im = null; self._n = null; self._i = null; self._c = null; self._str = null; self._strp = null; self._tex = null; self._dec = null; self._norm = null; self._int = null; self._rem = null; return self; } ,isReal: function() { var self = this, Arithmetic = Abacus.Arithmetic; return self.im.equ(Arithmetic.O); } ,isImag: function() { var self = this, O = Abacus.Arithmetic.O; return self.re.equ(O) && !self.im.equ(O); } ,isInt: function() { var self = this; return self.isReal() && self.re.isInt(); } ,isGauss: function() { // is Gaussian integer var self = this; return self.re.isInt() && self.im.isInt(); } ,equ: function(a) { var self = this, Arithmetic = Abacus.Arithmetic; if (is_instance(a, Complex)) return self.re.equ(a.re) && self.im.equ(a.im); else if (is_instance(a, Numeric) || Arithmetic.isNumber(a)) return self.re.equ(a) && self.im.equ(Arithmetic.O); else if (is_instance(a, INumber)) return a.equ(self); else if (is_string(a)) return (a === self.toString()) || (a === self.toTex()) || (a === self.toDec()); return false; } ,gt: function(a) { var self = this, Arithmetic = Abacus.Arithmetic; if (is_instance(a, Complex)) { if (self.isReal() && a.isReal()) return self.re.gt(a.re); else if (self.isImag() && a.isImag()) return self.im.gt(a.im); return self.norm().gt(a.norm()); } else if ((is_instance(a, Numeric) || Arithmetic.isNumber(a)) && self.isReal()) { return self.re.gt(a); } else if (is_instance(a, INumber)) { return a.lt(self); } return false; } ,gte: function(a) { var self = this, Arithmetic = Abacus.Arithmetic; if (is_instance(a, Complex)) { if (self.isReal() && a.isReal()) return self.re.gte(a.re); else if (self.isImag() && a.isImag()) return self.im.gte(a.im); return self.norm().gte(a.norm()); } else if ((is_instance(a, Numeric) || Arithmetic.isNumber(a)) && self.isReal()) { return self.re.gte(a); } else if (is_instance(a, INumber)) { return a.lte(self); } return false; } ,lt: function(a) { var self = this, Arithmetic = Abacus.Arithmetic; if (is_instance(a, Complex)) { if (self.isReal() && a.isReal()) return self.re.lt(a.re); else if (self.isImag() && a.isImag()) return self.im.lt(a.im); return self.norm().lt(a.norm()); } else if ((is_instance(a, Numeric) || Arithmetic.isNumber(a)) && self.isReal()) { return self.re.lt(a); } else if (is_instance(a, INumber)) { return a.gt(self); } return false; } ,lte: function(a) { var self = this, Arithmetic = Abacus.Arithmetic; if (is_instance(a, Complex)) { if (self.isReal() && a.isReal()) return self.re.lte(a.re); else if (self.isImag() && a.isImag()) return self.im.lte(a.im); return self.norm().lte(a.norm()); } else if ((is_instance(a, Numeric) || Arithmetic.isNumber(a)) && self.isReal()) { return self.re.lte(a); } else if (is_instance(a, INumber)) { return a.gte(self); } return false; } ,real: function() { return this.re; } ,imag: function() { return this.im; } ,norm: function() { var self = this, real, imag, two = Abacus.Arithmetic.II; if (null == self._norm) { real = self.re; imag = self.im; self._norm = real.pow(two).add(imag.pow(two)); } return self._norm; } ,abs: function() { var self = this; return Complex(self.re.abs(), self.im.abs()); } ,neg: function() { var self = this; if (null == self._n) { self._n = Complex(self.re.neg(), self.im.neg()); self._n._n = self; } return self._n; } ,conj: function() { var self = this; if (null == self._c) { self._c = Complex(self.re, self.im.neg()); self._c._c = self; } return self._c; } ,rev: function() { var self = this; return Complex(self.im, self.re); } ,inv: function() { var self = this, Arithmetic = Abacus.Arithmetic, m; if (null == self._i) { if (self.equ(Arithmetic.O)) throw new Error('Division by zero in inverse in Abacus.Complex!'); m = self.norm(); self._i = Complex(self.re.div(m), self.im.div(m).neg()); self._i._i = self; } return self._i; } ,add: function(a) { var self = this, Arithmetic = Abacus.Arithmetic; if (is_instance(a, Complex)) return Complex(self.re.add(a.re), self.im.add(a.im)); else if (is_instance(a, Numeric) || Arithmetic.isNumber(a)) return Complex(self.re.add(a), self.im); else if (is_instance(a, INumber)) return a.add(self); return self; } ,sub: function(a) { var self = this, Arithmetic = Abacus.Arithmetic; if (is_instance(a, Complex)) return Complex(self.re.sub(a.re), self.im.sub(a.im)); else if (is_instance(a, Numeric) || Arithmetic.isNumber(a)) return Complex(self.re.sub(a), self.im); else if (is_instance(a, INumber)) return a.neg().add(self); return self; } ,mul: function(a) { var self = this, Arithmetic = Abacus.Arithmetic, k1, k2, k3, x1, x2, y1, y2; if (is_instance(a, Complex)) { if (self.isReal()) { return Complex(a.re.mul(self.re), a.im.mul(self.re)); } else if (self.isImag()) { return Complex(a.im.mul(self.im).neg(), a.re.mul(self.im)); } else if (a.isReal()) { return Complex(self.re.mul(a.re), self.im.mul(a.re)); } else if (a.isImag()) { return Complex(self.im.mul(a.im).neg(), self.re.mul(a.im)); } else { // fast complex multiplication x1 = self.re; x2 = a.re; y1 = self.im; y2 = a.im; k1 = x1.mul(x2.add(y2)); k2 = y2.mul(x1.add(y1)); k3 = x2.mul(y1.sub(x1)); return Complex(k1.sub(k2), k1.add(k3)); } } else if (is_instance(a, Numeric) || Arithmetic.isNumber(a)) { return Complex(self.re.mul(a), self.im.mul(a)); } else if (is_instance(a, INumber)) { return a.mul(self); } return self; } ,div: function(a) { var self = this, Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, m, k1, k2, k3, x1, x2, y1, y2; if (is_instance(a, Complex)) { if (a.equ(O)) throw new Error('Division by zero in Abacus.Complex!'); if (a.isReal()) { return Complex(self.re.div(a.re), self.im.div(a.re)); } else if (a.isImag()) { return Complex(self.im.div(a.im), self.re.div(a.im).neg()); } else { // fast complex multiplication for inverse m = a.norm(); x1 = self.re; x2 = a.re.div(m); y1 = self.im; y2 = a.im.div(m).neg(); k1 = x1.mul(x2.add(y2)); k2 = y2.mul(x1.add(y1)); k3 = x2.mul(y1.sub(x1)); return Complex(k1.sub(k2), k1.add(k3)); } } else if (is_instance(a, Numeric) || Arithmetic.isNumber(a)) { if ((is_instance(a, Numeric) && a.equ(O)) || (Arithmetic.isNumber(a) && Arithmetic.equ(O, a))) throw new Error('Division by zero in Abacus.Complex!'); return Complex(self.re.div(a), self.im.div(a)); } return self; } ,mod: function(a, q) { var self = this, Arithmetic = Abacus.Arithmetic; if (is_instance(a, Numeric) || Arithmetic.isNumber(a)) return self.sub((is_instance(q, Complex) ? q : self.div(a).round()).mul(a)); return self; } ,divmod: function(a) { var self = this, q = self.div(a).round(); return [q, self.mod(a, q)]; } ,divides: function(a) { return !this.equ(Abacus.Arithmetic.O); } ,pow: function(n) { var self = this, Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, I = Arithmetic.I, pow, e; n = Integer.cast(n); if (n.gt(MAX_DEFAULT)) return null; if (self.equ(O)) { if (n.lt(O)) throw new Error('Zero denominator in negative power in Abacus.Complex!'); return Complex.Zero(); } if (n.equ(O)) return Complex.One(); if (n.equ(I)) return self; if (n.lt(O)) { self = self.inv(); n = n.neg(); } n = Arithmetic.val(n.num); e = self; pow = Complex.One(); while (0 !== n) { // exponentiation by squaring if (n & 1) pow = pow.mul(e); n >>= 1; e = e.mul(e); } return pow; } ,rad: function(n) { var self = this, Arithmetic = Abacus.Arithmetic, norm; n = Integer.cast(n); if (n.equ(Arithmetic.I)) { return self; } if (n.equ(Arithmetic.II)) { // https://en.wikipedia.org/wiki/Complex_number#Square_root if (self.imag().equ(0)) { return self.real().lt(0) ? Complex(Rational.Zero(), self.real().abs().rad(n)) : Complex(self.real().rad(n), Rational.Zero()); } else { norm = self.norm().rad(2); return Complex(norm.add(self.real()).div(2).rad(n), norm.sub(self.real()).div(2).rad(n).mul(self.imag().lt(0) ? -1 : 1)); } } return kthroot(self, n); } ,simpl: function() { var self = this; if (!self._simpl) { // simplify self.re.simpl(); self.im.simpl(); self._str = null; self._strp = null; self._tex = null; self._simpl = true; } return self; } ,round: function(absolute) { absolute = false!==absolute; var self = this; return Complex(self.re.round(absolute), self.im.round(absolute)); // return integer part } ,integer: function() { var self = this; if (null == self._int) self._int = Complex(self.re.integer(), self.im.integer()); // return integer part return self._int; } ,remainder: function() { var self = this; if (null == self._rem) self._rem = Complex(self.re.remainder(), self.im.remainder()); // return remainder part return self._rem; } ,tuple: function() { return [this.re, this.im]; } ,valueOf: function() { return this.re.valueOf(); } ,toString: function(parenthesized) { var self = this, Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, zr; if (null == self._str) { zr = self.re.equ(O); self._str = (zr ? '' : self.re.toString()) + (self.im.equ(O) ? '' : ((self.im.gt(O) ? (zr ? '' : '+') : '') + (self.im.equ(Arithmetic.I) ? '' : (self.im.equ(Arithmetic.J) ? '-' : (self.im.toString(true)+'*'))) + Complex.Symbol)); if (!self._str.length) self._str = '0'; self._strp = (zr ? '' : self.re.toString(true)) + (self.im.equ(O) ? '' : ((self.im.gt(O) ? (zr ? '' : '+') : '') + (self.im.equ(Arithmetic.I) ? '' : (self.im.equ(Arithmetic.J) ? '-' : (self.im.toString(true)+'*'))) + Complex.Symbol)); if (!self._strp.length) self._strp = '0'; } return parenthesized ? self._strp : self._str; } ,toTex: function() { var self = this, Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, zr; if (null == self._tex) { zr = self.re.equ(O); self._tex = (zr ? '' : self.re.toTex()) + (self.im.equ(O) ? '' : ((self.im.gt(O) ? (zr ? '' : '+') : '') + (self.im.equ(Arithmetic.I) ? '' : (self.im.equ(Arithmetic.J) ? '-' : self.im.toTex()))+Complex.Symbol)); if (!self._tex.length) self._tex = '0'; } return self._tex; } ,toDec: function(precision) { var self = this, Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, zr, dec; if (null == self._dec) { zr = self.re.equ(O); self._dec = (zr ? '' : self.re.toDec()) + (self.im.equ(O) ? '' : ((self.im.gt(O) ? (zr ? '' : '+') : '') + (self.im.equ(Arithmetic.I) ? '' : (self.im.equ(Arithmetic.J) ? '-' : (self.im.toDec()))) + Complex.Symbol)); if (!self._dec.length) self._dec = '0'; } if (is_number(precision) && 0<=precision) { zr = self.re.equ(O); dec = (zr ? '' : self.re.toDec(precision)) + (self.im.equ(O) ? '' : ((self.im.gt(O) ? (zr ? '' : '+') : '') + (self.im.equ(Arithmetic.I) ? '' : (self.im.equ(Arithmetic.J) ? '-' : (self.im.toDec(precision)))) + Complex.Symbol)); if (!dec.length) { dec = '0'; if (0 n) return null; // not supported return 1 === n ? Complex.One() : Complex.Zero(); } ,evaluate: function(symbolValues) { var self = this; symbolValues = symbolValues || {}; return Complex.cast(symbolValues[self.sym] || 0); } ,toString: function() { return this.sym; } ,toTex: function() { var self = this; if (null == self._tex) self._tex = to_tex(self.sym); return self._tex; } }); // Represents a power term in algebraic expressions of general base to some general exponent PowTerm = Class(Symbolic, { constructor: function PowTerm(base, exp) { var self = this, p; if (!is_instance(self, PowTerm)) return new PowTerm(base, exp); if (is_instance(base, PowTerm)) { self.base = base.base; self.exp = base.exp; } else if (is_instance(base, [INumber, Func])) { self.base = base; self.exp = is_instance(exp, [INumber, Func]) ? exp : Rational.cast(null == exp ? 1 : exp); } else if (is_string(base)) { p = PowTerm.fromString(base, false); self.base = p[0]; self.exp = p[1]; } else { self.base = Complex.One(); self.exp = Rational.One(); } } ,__static__: { Symbol: SymbolTerm ,fromString: function(s, as_pow) { var i, b, e; s = trim(String(s)); if (-1 !== (i=s.indexOf('^'))) { e = s.slice(i+1); if (('{' === e.charAt(0)) && ('}' === e.charAt(e.length-1))) e = trim(e.slice(1,-1)); s = s.slice(0, i); } else { e = '1'; } b = SymbolTerm.fromString(trim(s)); e = Rational.fromString(e); return false !== as_pow ? new PowTerm(b, e) : [b, e]; } } ,base: null ,exp: null ,_str: null ,_tex: null ,dispose: function() { var self = this; self.base = null; self.exp = null; self._str = null; self._tex = null; return self; } ,c: function() { return Complex.One(); } ,isConst: function() { var self = this; return self.base.isConst() && self.exp.isConst(); } ,isReal: function() { var self = this; return self.base.isReal() && self.exp.isReal(); } ,isImag: function() { var self = this; return self.base.isImag() && self.exp.isReal(); } ,real: function() { var self = this; return PowTerm(self.base.real(), self.exp.real()); } ,imag: function() { var self = this; return PowTerm(self.base.imag(), self.exp.imag()); } ,equ: function(a) { var self = this, Arithmetic = Abacus.Arithmetic; if (is_instance(a, PowTerm)) return self.base.equ(a.base) && self.exp.equ(a.exp); else if (is_instance(a, [Func, SymbolTerm, Numeric]) || Arithmetic.isNumber(a)) return self.base.equ(a) && self.exp.equ(Arithmetic.I); else if (is_instance(a, INumber)) return a.equ(self); else if (is_string(a)) return (a === self.toString()) || (a === self.toTex()); return false; } ,gt: function(a) { var self = this, Arithmetic = Abacus.Arithmetic; if (is_instance(a, PowTerm)) return (self.exp.equ(a.exp) && self.base.gt(a.base)) || (self.base.equ(a.base) && self.exp.gt(a.exp)); else if (is_instance(a, [Func, SymbolTerm])) return self.base.equ(a) && self.exp.gt(Arithmetic.I); else if (is_instance(a, Numeric) || Arithmetic.isNumber(a)) return (self.exp.equ(Arithmetic.I) && self.base.gt(a)) || (self.base.equ(a) && self.exp.gt(Arithmetic.I)); else if (is_instance(a, INumber)) return a.lt(self); return false; } ,gte: function(a) { var self = this, Arithmetic = Abacus.Arithmetic; if (is_instance(a, PowTerm)) return (self.exp.equ(a.exp) && self.base.gte(a.base)) || (self.base.equ(a.base) && self.exp.gte(a.exp)); else if (is_instance(a, [Func, SymbolTerm])) return self.base.equ(a) && self.exp.gte(Arithmetic.I); else if (is_instance(a, Numeric) || Arithmetic.isNumber(a)) return (self.exp.equ(Arithmetic.I) && self.base.gte(a)) || (self.base.equ(a) && self.exp.gte(Arithmetic.I)); else if (is_instance(a, INumber)) return a.lte(self); return false; } ,lt: function(a) { var self = this, Arithmetic = Abacus.Arithmetic; if (is_instance(a, PowTerm)) return (self.exp.equ(a.exp) && self.base.lt(a.base)) || (self.base.equ(a.base) && self.exp.lt(a.exp)); else if (is_instance(a, [Func, SymbolTerm])) return self.base.equ(a) && self.exp.lt(Arithmetic.I); else if (is_instance(a, Numeric) || Arithmetic.isNumber(a)) return (self.exp.equ(Arithmetic.I) && self.base.lt(a)) || (self.base.equ(a) && self.exp.lt(Arithmetic.I)); else if (is_instance(a, INumber)) return a.gt(self); return false; } ,lte: function(a) { var self = this, Arithmetic = Abacus.Arithmetic; if (is_instance(a, PowTerm)) return (self.exp.equ(a.exp) && self.base.lte(a.base)) || (self.base.equ(a.base) && self.exp.lte(a.exp)); else if (is_instance(a, [Func, SymbolTerm])) return self.base.equ(a) && self.exp.lte(Arithmetic.I); else if (is_instance(a, Numeric) || Arithmetic.isNumber(a)) return (self.exp.equ(Arithmetic.I) && self.base.lte(a)) || (self.base.equ(a) && self.exp.lte(Arithmetic.I)); else if (is_instance(a, INumber)) return a.gte(self); return false; } ,abs: function() { var self = this; return is_instance(self.base, SymbolTerm) ? self : PowTerm(self.base.abs(), self.exp); } ,neg: function() { var self = this; return MulTerm(self, -1); } ,conj: function() { var self = this; return is_instance(self.base, SymbolTerm) ? self : PowTerm(self.base.conj(), self.exp); } ,inv: function() { var self = this; return PowTerm(self.base, self.exp.neg()); } ,add: function(a) { var self = this, Arithmetic = Abacus.Arithmetic; if (is_instance(a, [Numeric, SymbolTerm, PowTerm, MulTerm, Func]) || Arithmetic.isNumber(a)) return Expr([self, a]); else if (is_instance(a, INumber)) return a.add(self); return self; } ,sub: function(a) { var self = this, Arithmetic = Abacus.Arithmetic; if (is_instance(a, Numeric) || Arithmetic.isNumber(a)) return Expr([self, Arithmetic.isNumber(a) ? Arithmetic.neg(a) : a.neg()]); else if (is_instance(a, [SymbolTerm, PowTerm, MulTerm, Func])) return Expr([self, a.neg()]); else if (is_instance(a, INumber)) return a.neg().add(self); return self; } ,mul: function(a) { var self = this, Arithmetic = Abacus.Arithmetic; if (is_instance(a, PowTerm)) return self.base.equ(a.base) ? PowTerm(self.base, self.exp.add(a.exp)) : MulTerm([self, a]); else if (is_instance(a, [Func, SymbolTerm])) return self.base.equ(a) ? PowTerm(self.base, self.exp.add(Arithmetic.I)) : MulTerm([self, a]); else if (is_instance(a, Numeric) || Arithmetic.isNumber(a)) return MulTerm(self, a); else if (is_instance(a, INumber)) return a.mul(self); return self; } ,div: function(a) { var self = this, Arithmetic = Abacus.Arithmetic; if (is_instance(a, PowTerm)) return self.base.equ(a.base) ? PowTerm(self.base, self.exp.sub(a.exp)) : MulTerm([self, a.inv()]); else if (is_instance(a, [Func, SymbolTerm])) return self.base.equ(a) ? PowTerm(self.base, self.exp.sub(Arithmetic.I)) : MulTerm([self, PowTerm(a, Rational.MinusOne())]); else if (is_instance(a, Numeric) || Arithmetic.isNumber(a)) return MulTerm(self, Arithmetic.isNumber(a) ? Rational(Arithmetic.I, a) : a.inv()); else if (is_instance(a, INumber)) return a.inv().mul(self); return self; } ,pow: function(n) { var self = this; return PowTerm(self.base, self.exp.mul(n)); } ,rad: function(n) { var self = this; return PowTerm(self.base, self.exp.div(n)); } ,d: function(n) { // nth order formal derivative var self = this, Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, d, k; if (null == n) n = 1; n = +n; if (0 > n) return null; // not supported k = self.exp.sub(n); if (self.exp.lt(O) || !is_instance(k, Numeric) || !k.isReal() || !k.isInt() || k.gte(O)) { d = MulTerm(PowTerm(self.base, k), operate(function(f, i){ return self.exp.sub(i).mul(f); }, Arithmetic.I, null, 0, n-1, 1)); } else { d = MulTerm(1, O); } return d; } ,evaluate: function(symbolValues) { var self = this, Arithmetic = Abacus.Arithmetic, b, e; symbolValues = symbolValues || {}; e = Rational.cast(is_instance(self.exp, Symbolic) ? self.exp.evaluate(symbolValues) : self.exp).simpl(); b = Complex.cast(is_instance(self.base, Symbolic) ? self.base.evaluate(symbolValues) : self.base).simpl(); return b.equ(Arithmetic.O) ? Complex.Zero() : b.pow(e.num).rad(e.den); } ,toString: function() { var self = this, Arithmetic = Abacus.Arithmetic, O = Arithmetic.O; if (null == self._str) self._str = self.exp.equ(O) ? '1' : (self.exp.equ(Arithmetic.I) ? self.base.toString() : ((is_instance(self.base, SymbolTerm) ? self.base.toString() : '('+self.base.toString()+')') + (is_instance(self.exp, SymbolTerm)||(is_instance(self.exp, Numeric)&&self.exp.isReal())||(is_instance(self.exp, Poly)&&self.exp.isConst(true)&&self.exp.c().isReal()) ? ('^'+self.exp.toString(true)) : ('^('+self.exp.toString()+')')))); return self._str; } ,toTex: function() { var self = this, Arithmetic = Abacus.Arithmetic, O = Arithmetic.O; if (null == self._tex) self._tex = self.exp.equ(O) ? '1' : (self.exp.equ(Arithmetic.I) ? self.base.toTex() : ((is_instance(self.base, SymbolTerm) ? self.base.toTex() : '('+self.base.toTex()+')') + ('^{'+self.exp.toTex()+'}'))); return self._tex; } }); // Represents multiplicative terms in (linear) algebraic expressions, including terms with mixed factors of (powers of) symbolic variables MulTerm = Class(Symbolic, { constructor: function MulTerm(s, c) { var self = this, Arithmetic = Abacus.Arithmetic, f, i, l; if (!is_instance(self, MulTerm)) return new MulTerm(s, c); if (is_instance(s, MulTerm)) { c = s.factors['1']; self.symbol = s.symbol; self.symbolTex = s.symbolTex; s = s.factors; f = c; self.factors = Obj(); self.factors['1'] = f; if (!self.factors['1'].equ(Arithmetic.O)) MulTerm.Merge(s, self); } else if (is_instance(s, [SymbolTerm, Func, PowTerm])) { if (is_instance(s, [SymbolTerm, Func])) s = PowTerm(s, Arithmetic.I); f = Complex.cast(null == c ? Arithmetic.I : c); // default self.symbol = s.toString(); self.symbolTex = s.toTex(); self.factors = Obj(); self.factors['1'] = f; if (!self.factors['1'].equ(Arithmetic.O)) MulTerm.Merge(s, self); } else if (is_instance(s, Numeric)/* || Arithmetic.isNumber(s)*/) { self.symbol = '1'; self.symbolTex = '1'; self.factors = Obj(); self.factors['1'] = Complex.cast(s); } else if (is_string(s)) { c = Complex.cast(null == c ? Arithmetic.I : c); // default self.factors = Obj(); self.factors['1'] = c; if (!self.factors['1'].equ(Arithmetic.O)) MulTerm.Merge(s, self); MulTerm.Symbol(self); } else if (is_array(s)) { c = Complex.cast(null == c ? Arithmetic.I : c); // default self.factors = Obj(); self.factors['1'] = c; if (!self.factors['1'].equ(Arithmetic.O)) { for (i=0,l=s.length; i n) return null; // not supported if (factors['1'].equ(O) || ('1' === x) || !HAS.call(factors, x)) return MulTerm({}, O); fac = {}; c = I; for (f in factors) { if (!HAS.call(factors, f) || ('1' === f)) continue; if (x === f) { d = factors[f].d(n); if (HAS.call(d.factors, f)) fac[f] = d.factors[f]; c = d.c().mul(c); } else { fac[f] = factors[f]; } } return MulTerm(fac, factors['1'].mul(c)); } ,evaluate: function(symbolValues) { var self = this, Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, I = Arithmetic.I, res; symbolValues = symbolValues || {}; if ('1'===self.symbol) res = self.factors['1']; else res = self.symbols().reduce(function(r, f){ return r.equ(O) ? Complex.Zero() : r.mul('1'===f ? self.factors['1'] : self.factors[f].evaluate(symbolValues)); }, Complex.One()); return res; } ,toString: function() { var self = this, Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, f1; if (null == self._str) { f1 = self.factors['1']; if (f1.equ(O)) self._str = '0'; else if (f1.isReal()) self._str = ('1'===self.symbol) ? f1.real().toString() : ((f1.real().equ(Arithmetic.J) ? '-' : (f1.real().equ(Arithmetic.I) ? '' : (f1.real().toString(true)+'*'))) + self.symbol); else self._str = ('1'===self.symbol) ? ('('+f1.toString()+')') : (('('+f1.toString()+')*') + self.symbol); } return self._str; } ,toTex: function() { var self = this, Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, f1; if (null == self._tex) { f1 = self.factors['1']; if (f1.equ(O)) self._tex = '0'; else if (f1.isReal()) self._tex = ('1'===self.symbol) ? f1.real().toTex() : ((f1.real().equ(Arithmetic.J) ? '-' : (f1.real().equ(Arithmetic.I) ? '' : f1.real().toTex())) + self.symbolTex); else self._tex = ('1'===self.symbol) ? ('('+f1.toTex()+')') : (('('+f1.toTex()+')') + self.symbolTex); } return self._tex; } }); // Abacus.Expr, represents (symbolic) (linear) algebraic expressions of sums of (multiplicative) terms AddTerm = Expr = Abacus.Expr = Class(Symbolic, { constructor: function Expr(/* args */) { var self = this, i, l, terms = arguments.length && (is_array(arguments[0]) || is_args(arguments[0])) ? arguments[0] : arguments; if (!is_instance(self, Expr)) return new Expr(terms); self.terms = Obj(); self.terms['1'] = MulTerm(1, Complex.Zero()); // constant term is default for (i=0,l=terms.length; i>= 1; e = e.mul(e); } return pow; } ,rad: function(n) { var self = this, Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, I = Arithmetic.I, factors, f; n = Integer.cast(n); if (self.equ(O)) return Expr(); if (n.equ(O)) return null; // undefined if (n.equ(I)) return self; return Expr(1===self.symbols().length ? self.terms['1'].rad(n) : MulTerm(PowTerm(self, Rational(I, n.num)), I)); } ,d: function(x, n) { var self = this; // nth order formal derivative with respect to symbol x if (null == n) n = 1; n = +n; x = String(x || 'x'); return 0 > n ? null : Expr(self.symbols().map(function(t){return '1' === t ? Abacus.Arithmetic.O : self.terms[t].d(x, n);})); } ,evaluate: function(symbolValues) { var self = this, Arithmetic = Abacus.Arithmetic, O = Arithmetic.O; symbolValues = symbolValues || {}; return self.symbols().reduce(function(r, t){ return r.add(self.terms[t].evaluate(symbolValues)); }, Complex.Zero()); } ,toString: function() { var self = this, Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, keys, i, l, t, f1, out = '', prev = false; if (null == self._str) { keys = self.symbols(); l = keys.length; for (i=0; i=l) || ('/'===s.charAt(i)))) { if ((i n) { n = -n; t = num; num = den; den = t; } if (0 === n) return RationalExpr(Arithmetic.I); else if (1 === n) return RationalExpr(num, den); else return RationalExpr(num.pow(n), den.pow(n)); } ,rad: function(n) { var self = this, Arithmetic = Abacus.Arithmetic; n = Integer.cast(n); if (n.equ(Arithmetic.I)) return self; return RationalExpr(self.num.rad(n), self.den.rad(n)); } ,d: function(x, n) { // partial rational (formal) derivative of nth order with respect to symbol x var self = this, num, den, d_num, d_den, Arithmetic = Abacus.Arithmetic; if (null == n) n = 1; n = Arithmetic.val(n); if (0 > n) return null; // not supported else if (0 === n) return self; num = self.num; den = self.den; while (0, <=, >=, <> RelOp = Abacus.RelOp = Class(Op, { constructor: function RelOp(lhs, op, rhs) { var self = this; if (!is_instance(self, RelOp)) return new RelOp(lhs, op, rhs); if (is_instance(lhs, RelOp)) { self.lhs = lhs.lhs; self.op = lhs.op; self.rhs = lhs.rhs; } else { op = String(op||'=').toLowerCase(); if (null == lhs) lhs = RationalExpr(); if (null == rhs) rhs = RationalExpr(); if (!is_instance(lhs, [Expr, RationalExpr, Func])) lhs = RationalExpr(lhs); if (!is_instance(rhs, [Expr, RationalExpr, Func])) rhs = RationalExpr(rhs); self.lhs = lhs; self.rhs = rhs; self.op = RelOp.OP(op) } } ,__static__: { OP: function(op) { op = String(op).toLowerCase(); if ('<' === op || '\\lt' ===op) op = '<'; else if ('>' === op || '\\gt' ===op) op = '>'; else if ('>=' === op || '=>' === op || '\\le' ===op) op = '>='; else if ('<=' === op || '=<' === op || '\\ge' ===op) op = '<='; else if ('<>' === op || '!=' === op || '\\ne' ===op) op = '<>'; else if ('~' === op || '\\sim' ===op) op = '~'; else op = '='; return op; } ,DUAL: function(op) { op = RelOp.OP(op); if ('<' === op) return '>'; else if ('>' === op) return '<'; else if ('>=' === op) return '<='; else if ('<=' === op) return '>='; return op; } ,EQU: function(lhs, rhs) { return new RelOp(lhs, '=', rhs); } ,NEQ: function(lhs, rhs) { return new RelOp(lhs, '<>', rhs); } ,LT: function(lhs, rhs) { return new RelOp(lhs, '<', rhs); } ,LTE: function(lhs, rhs) { return new RelOp(lhs, '<=', rhs); } ,GT: function(lhs, rhs) { return new RelOp(lhs, '>', rhs); } ,GTE: function(lhs, rhs) { return new RelOp(lhs, '>=', rhs); } ,SIM: function(lhs, rhs) { return new RelOp(lhs, '~', rhs); } ,fromString: function(s) { var args = String(s).split(/\\sim|\\lt|\\gt|\\le|\\ge|\\ne|\\eq|=<|<=|>=|=>|<>|!=|<|>|=|~/gm), op = ['\\sim','\\lt','\\gt','\\le','\\ge','\\ne','\\eq','=<','<=','>=','=>','<>','!=','<','>','=','~'].reduce(function(op, opp){ var p = s.indexOf(opp); if (-1 < p && p < op[1]) op = [opp, p]; return op; }, ['=',Infinity])[0]; return new RelOp(RationalExpr.fromString(args[0]), op, args.length>1?RationalExpr.fromString(args[1]):RationalExpr()); } } ,lhs: null ,rhs: null ,dispose: function() { var self = this; self.lhs = null; self.rhs = null; self.op = null; return self; } ,clone: function() { var self = this; return new self[CLASS](self.lhs, self.op, self.rhs); } ,equ: function(rop) { var self = this; if (is_instance(rop, RelOp)) { if (self.op===rop.op && self.lhs.equ(rop.lhs) && self.rhs.equ(rop.rhs)) return true; else if (self.op===RelOp.DUAL(rop.op) && self.lhs.equ(rop.rhs) && self.rhs.equ(rop.lhs)) return true; } return false; } ,neg: function() { var self = this; return new RelOp(self.lhs.neg(), RelOp.DUAL(self.op), self.rhs.neg()); } ,add: function(term) { var self = this, op = self.op; return new RelOp(self.lhs.add(term), op, self.rhs.add(term)); } ,sub: function(term) { var self = this, op = self.op; return new RelOp(self.lhs.sub(term), op, self.rhs.sub(term)); } ,mul: function(term) { var self = this, op = self.op, Arithmetic = Abacus.Arithmetic; if ((Arithmetic.isNumber(term) && Arithmetic.lt(term, 0)) || (is_instance(term, Numeric) && term.lt(0))) op = RelOp.DUAL(op); return new RelOp(self.lhs.mul(term), op, self.rhs.mul(term)); } ,div: function(term) { var self = this, op = self.op, Arithmetic = Abacus.Arithmetic; if ((Arithmetic.isNumber(term) && Arithmetic.lt(term, 0)) || (is_instance(term, Numeric) && term.lt(0))) op = RelOp.DUAL(op); return new RelOp(self.lhs.div(term), op, self.rhs.div(term)); } ,evaluate: function(symbolValues) { symbolValues = symbolValues || {}; var self = this, op = self.op, res = false, lhs = self.lhs.evaluate(symbolValues), rhs = self.rhs.evaluate(symbolValues); if ('>' === op) res = lhs.gt(rhs); else if ('<' === op) res = lhs.lt(rhs); else if ('>=' === op) res = lhs.gte(rhs); else if ('<=' === op) res = lhs.lte(rhs); else if ('<>' === op) res = !lhs.equ(rhs); else if ('~' === op) res = true; else /*if ('=' === op)*/ res = lhs.equ(rhs); return res; } ,toString: function() { var self = this, op = self.op; return self.lhs.toString()+' '+op+' '+self.rhs.toString(); } ,toTex: function() { var self = this, op = self.op; if ('>=' === op) op = '\\ge'; else if ('<=' === op) self.op = '\\le'; else if ('<>' === op) self.op = '\\ne'; else if ('~' === op) op = '\\sim'; return self.lhs.toTex()+' '+op+' '+self.rhs.toTex(); } }); // Abacus.Func, represents a functional operator, eg min, max, exp, log, sin, cos, .. Func = Abacus.Func = Class(Op, { constructor: function Func(func, args, evaluator, derivative) { var self = this; if (!is_instance(self, Func)) return new Func(func, args, evaluator, derivative); if (is_instance(func, Func)) { self.func = func.op; self.args = func.args; self._eval = evaluator || func._eval; self._deriv = derivative || func._deriv; } else { func = String(func||'').toLowerCase(); if (null == args || !args.length) args = []; self.op = func; self.args = args.map(function(arg){ if (!is_instance(arg, [Expr, RationalExpr, Func])) arg = RationalExpr(arg); return arg; }); self._eval = evaluator || null; self._deriv = derivative || null } } ,__static__: { MIN: function(args) { return Func('min', args, nmin); } ,MAX: function(args) { return Func('max', args, nmax); } } ,args: null ,_eval: null ,_deriv: null ,dispose: function() { var self = this; self._eval = null; self._deriv = null; self.args = null; self.op = null; return self; } ,clone: function() { var self = this; return new self[CLASS](self.op, self.args, self._eval, self._deriv); } ,isReal: function() { var args = self.args; return args.filter(function(arg){return arg.isReal();}).length===args.length; } ,isImag: function() { var args = self.args; return args.filter(function(arg){return arg.isImag();}).length===args.length; } ,real: function() { var self = this; return Func(self.op, self.args.map(function(arg){return arg.real();}), self._eval, self._deriv); } ,imag: function() { var self = this; return Func(self.op, self.args.map(function(arg){return arg.imag();}), self._eval, self._deriv); } ,equ: function(term) { var self = this; if (is_instance(term, Func)) { return self.op === term.op && self.args.filter(function(arg, i){ return i n && is_callable(derivative)) { d = derivative.apply(self, self.args); if (1 < n) d = d.d(x, n-1); return d; } return self; } ,evaluate: function(symbolValues) { symbolValues = symbolValues || {}; var self = this, args = self.args, evaluator = self._eval; return is_callable(evaluator) ? evaluator.apply(self, args.map(function(arg){return arg.evaluate(symbolValues);})) : Complex.Zero(); } ,toString: function() { var self = this, args = self.args, op = self.op; if (('min' === op || 'max' === op) && 1 === args.length) return String(args[0]); return op+'('+args.map(String).join(',')+')'; } ,toTex: function() { var self = this, args = self.args, op = self.op; if (('min' === op || 'max' === op) && 1 === args.length) return Tex(args[0]); return '\\'+op+'('+args.map(Tex).join(',')+')'; } }); // Represents a (univariate) polynomial term with coefficient and exponent in Polynomial non-zero sparse representation UniPolyTerm = Class({ constructor: function UniPolyTerm(c, e, ring) { var self = this; if (!is_instance(self, UniPolyTerm)) return new UniPolyTerm(c, e, ring); if (is_instance(c, UniPolyTerm)){ring = ring || c.ring; e = c.e; c = c.c;} self.ring = is_instance(ring, Ring) ? ring : Ring.Q(); self.c = is_instance(c, [RationalFunc, RationalExpr]) ? c : self.ring.cast(c||0); self.e = +(e||0); } ,__static__: { isNonZero: function(t) { return is_instance(t, UniPolyTerm) && !t.c.equ(Abacus.Arithmetic.O); } ,cmp: function(t1, t2, full) { var res = t1.e-t2.e; if ((true===full) && (0===res)) return t1.c.equ(t2.c) ? 0 : (t1.c.lt(t2.c) ? -1 : 1); return res; } ,sortDecr: function(t1, t2) { return UniPolyTerm.cmp(t2, t1); } ,gcd: function(t1, t2, full) { return UniPolyTerm(true===full ? (!(is_instance(t1.c, [RationalFunc, RationalExpr]) || is_instance(t2.c, [RationalFunc, RationalExpr])) && t1.ring.hasGCD() ? t1.ring.gcd(t1.c, t2.c) : t1.ring.One()) : t1.ring.One(), stdMath.min(t1.e, t2.e)); } ,lcm: function(t1, t2, full) { return UniPolyTerm(true===full ? (!(is_instance(t1.c, [RationalFunc, RationalExpr]) || is_instance(t2.c, [RationalFunc, RationalExpr])) && t1.ring.hasGCD() ? t1.ring.lcm(t1.c, t2.c) : t1.c.mul(t2.c)) : t1.c.mul(t2.c), stdMath.max(t1.e, t2.e)); } } ,ring: null ,c: null ,e: null ,dispose: function() { var self = this; self.ring = null; self.c = null; self.e = null; return self; } ,clone: function() { return new UniPolyTerm(this); } ,cast: function(ring) { var self = this; return ring===self.ring ? self : new UniPolyTerm(self.c, self.e, ring); } ,equ: function(term) { var self = this; return is_instance(term, UniPolyTerm) ? (self.c.equ(term.c) && self.e===term.e) : self.c.equ(term); } ,neg: function() { var self = this; return UniPolyTerm(self.c.neg(), self.e, self.ring); } ,add: function(term) { var self = this; return is_instance(term, UniPolyTerm) ? UniPolyTerm(self.c.add(term.c), self.e, self.ring) : UniPolyTerm(self.c.add(term), self.e, self.ring); } ,sub: function(term) { var self = this; return is_instance(term, UniPolyTerm) ? UniPolyTerm(self.c.sub(term.c), self.e, self.ring) : UniPolyTerm(self.c.sub(term), self.e, self.ring); } ,mul: function(term) { var self = this; return is_instance(term, UniPolyTerm) ? UniPolyTerm(self.c.mul(term.c), self.e+term.e, self.ring) : UniPolyTerm(self.c.mul(term), self.e, self.ring); } ,div: function(term) { var self = this; return is_instance(term, UniPolyTerm) ? UniPolyTerm(self.c.div(term.c), stdMath.max(0, self.e-term.e), self.ring) : UniPolyTerm(self.c.div(term), self.e, self.ring); } ,divides: function(term) { var self = this; return (self.e <= term.e) && self.c.divides(term.c); } ,pow: function(k) { var self = this; k = +k; return 1===k ? self : UniPolyTerm(self.c.pow(k), stdMath.floor(self.e*k), self.ring); } ,rad: function(k) { var self = this; k = +k; return 1===k ? self : UniPolyTerm(self.c.rad(k), stdMath.max(stdMath.floor(self.e/k), stdMath.min(1, self.e)), self.ring); } ,toTerm: function(symbol, asTex, monomialOnly, asDec, precision) { var t = this, e = t.e, c = t.c, term, Arithmetic = Abacus.Arithmetic; if (true===asDec) { term = 0 < e ? (symbol + (1 x.symbol ? [x.symbol, P.symbol] : [P.symbol, x.symbol]; return MultiPolynomial.Add(MultiPolynomial(x, symbol, P.ring), MultiPolynomial(P, symbol, P.ring), do_sub); } } else if (is_instance(x, Numeric) || Arithmetic.isNumber(x)) { // O(1) x = UniPolyTerm(x, 0, P.ring); if (!x.equ(Arithmetic.O)) { res = P.terms.length ? addition_sparse([P.terms.pop()], [x], UniPolyTerm, true===do_sub, P.ring) : [x]; P.terms = P.terms.concat(res); } } return P; } ,Mul: function(x, P) { var Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, i, symbol; if (!P.terms.length) return P; if (is_instance(x, Polynomial)) { if (x.symbol === P.symbol) { // O(n1*n2) P.terms = x.terms.length ? multiplication_sparse(P.terms, x.terms, UniPolyTerm, P.ring) : []; } else { // upgrade to multivariate polynomial symbol = P.symbol > x.symbol ? [x.symbol, P.symbol] : [P.symbol, x.symbol]; return MultiPolynomial.Mul(MultiPolynomial(x, symbol, x.ring), MultiPolynomial(P, symbol, P.ring)); } } else if (is_instance(x, Numeric) || Arithmetic.isNumber(x)) { // O(n) /*if (Arithmetic.isNumber(x))*/ x = P.ring.cast(x); if (x.equ(O)) { P.terms = []; } else if (x.equ(Arithmetic.I)) { // do nothing } else { for (i=P.terms.length-1; i>=0; i--) P.terms[i] = P.terms[i].mul(x); } } return P; } ,Div: function(P, x, q_and_r) { var Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, I = Arithmetic.I, symbol, q/*, r, d, diff, diff0*/; q_and_r = (true===q_and_r); if (is_instance(x, Polynomial)) { if (!x.terms.length) throw new Error('Division by zero in Abacus.Polynomial!'); if (x.isConst()) { // constant polynomial, simple numeric division x = x.cc(); q = x.equ(I) ? P : Polynomial(array(P.terms.length, function(i){ return P.terms[i].div(x); }), P.symbol, P.ring); return q_and_r ? [q, Polynomial.Zero(P.symbol, P.ring)] : q; } // polynomial long division // TODO: make it faster /*r = Polynomial(P); diff = r.deg()-x.deg(); if (0 <= diff) { q = array(diff+1, function(){return Rational.Zero();}); while (0 <= diff) { diff0 = diff; d = x.shift(diff); q[diff] = r.lc().div(d.lc()); r = Polynomial.Add(Polynomial.Mul(q[diff], d), r, true); diff = r.deg()-x.deg(); if ((diff === diff0)) break; // remainder won't change anymore } } else { q = []; } q = Polynomial(q, self.symbol);*/ if (x.symbol === P.symbol) { // sparse polynomial reduction/long division q = division_sparse(P.terms, x.terms, UniPolyTerm, q_and_r, P.ring); return q_and_r ? [Polynomial(q[0], P.symbol, P.ring), Polynomial(q[1], P.symbol, P.ring)] : Polynomial(q, P.symbol, P.ring); } else { // upgrade to multivariate polynomial symbol = P.symbol > x.symbol ? [x.symbol, P.symbol] : [P.symbol, x.symbol]; return MultiPolynomial.Div(MultiPolynomial(P, symbol, P.ring), MultiPolynomial(x, symbol, x.ring), q_and_r); } } else if (is_instance(x, Numeric) || Arithmetic.isNumber(x)) { /*if (Arithmetic.isNumber(x))*/ x = P.ring.cast(x); if (x.equ(O)) throw new Error('Division by zero in Abacus.Polynomial!'); q = x.equ(I) ? P : Polynomial(array(P.terms.length, function(i){ return P.terms[i].div(x); }), P.symbol, P.ring); return q_and_r ? [q, Polynomial.Zero(P.symbol, P.ring)] : q; } return P; } ,C: function(c, x, ring) { return new Polynomial(c || Abacus.Arithmetic.O, x||'x', ring||Ring.Q()); } ,gcd: polygcd ,xgcd: polyxgcd ,lcm: polylcm ,bezier: function(points, symbol) { // https://en.wikipedia.org/wiki/B%C3%A9zier_curve#Recursive_definition // https://en.wikipedia.org/wiki/De_Casteljau%27s_algorithm symbol = String(symbol||'x'); var ring = Ring.Q(), Bezier = Polynomial.Zero(symbol, ring), n, i, b0, b1, b11; if (is_array(points) && points.length) { n = points.length; b11 = Polynomial([1, -1], symbol, ring); b0 = Polynomial.One(symbol, ring).shift(n-1); b1 = Polynomial.One(symbol, ring); Bezier = Bezier.add(b0.mul(ring.cast(points[n-1]))); for (i=n-2; i>=0; i--) { b0 = b0.shift(-1); b1 = b1.mul(b11); Bezier = Bezier.add(b1.mul(b0).mul(factorial(n-1,i)).mul(ring.cast(points[i]))); } } return Bezier; } ,bezierThrough: function(knots, symbol) { // https://en.wikipedia.org/wiki/B%C3%A9zier_curve // https://www.particleincell.com/2012/bezier-splines/ // https://stackoverflow.com/questions/7715788/find-bezier-control-points-for-curve-passing-through-n-points symbol = String(symbol||'x'); var ring = Ring.Q(), i, computePoints, points, segments; computePoints = function(knots) { var i, p1, p2, a, b, c, r, m, n = knots.length-1; p1 = new Array(n); p2 = new Array(n); /*rhs vector*/ a = new Array(n); b = new Array(n); c = new Array(n); r = new Array(n); /*left most segment*/ a[0] = ring.Zero(); b[0] = ring.create(2); c[0] = ring.One(); r[0] = knots[0].add(knots[1].mul(2)); /*internal segments*/ for (i=1; i=0; --i) p1[i] = r[i].sub(c[i].mul(p1[i+1])).div(b[i]); /*we have p1, now compute p2*/ for (i=0;i=0; i--) { s = symbols[i]; tc = e.terms[s].c(); if (tc.equ(O)) continue; if (('1' === s)) terms['0'] = tc; else if ((x === s)) terms['1'] = tc; else if ((s.length > x.length+1) && (x+'^' === s.slice(0, x.length+1)) && (-1===s.indexOf('*'))) terms[s.slice(x.length+1)] = tc; } return new Polynomial(terms, x, ring); } ,fromString: function(s, symbol, ring) { var Arithmetic = Abacus.Arithmetic, terms = {}, _symbol = null, m, coeff, exp, sym, n, i, term_re = /(\(?(?:(?:[\+\-])?\s*\(?(?:(?:\\frac\{\-?\d+\}\{\-?\d+\})|(?:\-?\d+(?:\.\d*(?:\[\d+\])?)?(?:e-?\d+)?(?:\/\-?\d+)?))?\)?)(?:\s*(?:[\+\-])?\s*(?:\(?(?:(?:\\frac\{\-?\d+\}\{\-?\d+\})|(?:\-?\d+(?:\.\d*(?:\[\d+\])?)?(?:e-?\d+)?(?:\/\-?\d+)?))\)?\*?)?(?:[ij]))?\)?)?(?:\s*\*?\s*([a-zA-Z](?:_\{?\d+\}?)?)(?:\^\{?(\d+)\}?)?)?/g; ring = ring || Ring.Q(); s = trim(String(s)); if (!s.length) return Polynomial.Zero(symbol||'x', ring); while ((m=term_re.exec(s))) { // try to do best possible match of given string of polynomial terms if (!m[0].length) { if (term_re.lastIndex < s.length) { term_re.lastIndex++; continue; } else { break; // match at least sth } } if (!trim(m[0]).length) continue; // matched only spaces, continue if (m[2]) { sym = m[2]; if (-1 !== (i=sym.indexOf('_'))) { if ('{' === sym.charAt(i+1) && '}' === sym.charAt(sym.length-1)) sym = sym.slice(0,i+1)+sym.slice(i+2,-1); } if (symbol && (sym !== symbol)) { continue; // does not belong to same polynomial, has different symbol } else if (!symbol) { if (null == _symbol) { _symbol = sym; } else if (sym !== _symbol) { continue; // does not belong to same polynomial, has different symbol } } exp = m[3] || '1'; coeff = trim(m[1] || ''); if (('' === coeff) || ('+' === coeff) ) coeff = '1'; else if ('-' === coeff) coeff = '-1'; } else { exp = '0'; coeff = trim(m[1] || ''); if ('+' === coeff) coeff = '1'; else if ('-' === coeff) coeff = '-1'; else if ('' === coeff) coeff = '0'; } i = 0; while (i=0; i--) if (!terms[i].c.isInt()) return false; return true; } ,isReal: function() { // has real coefficients var self = this, terms = self.terms, i; if (!is_class(self.ring.NumberClass, Complex)) return true; for (i=terms.length-1; i>=0; i--) if (!terms[i].c.isReal()) return false; return true; } ,isImag: function() { // has imaginary coefficients var self = this, terms = self.terms, i; if (!is_class(self.ring.NumberClass, Complex)) return false; for (i=terms.length-1; i>=0; i--) if (!terms[i].c.isImag()) return false; return true; } ,isMono: function() { // is monomial var terms = this.terms; return (1===terms.length) && (0!==terms[0].e); } ,isConst: function() { return 0===this.deg(); } ,isUni: function(x, strict) { var self = this; x = String(x||'x'); if (self.symbol !== x) return false; return true===strict ? (0!==self.deg()) : true; } ,deg: function() { // polynomial degree var terms = this.terms; return terms.length ? terms[0].e : 0; } ,maxdeg: function() { // maximum polynomial degree return this.deg(); } ,mindeg: function() { // minimum polynomial degree var terms = this.terms; //return terms.length ? (0===terms[terms.length-1].e ? (10; i--) { if (!lc.divides(t[i].c)) { divides = false; break; } } // at least make positive return divides ? Polynomial(self.terms.map(function(t){return t.div(lc);}), self.symbol, self.ring) : (lc.lt(Arithmetic.O) ? self.neg() : self); } } ,primitive: function(and_content) { // factorise into content and primitive part // https://en.wikipedia.org/wiki/Factorization_of_polynomials#Primitive_part%E2%80%93content_factorization var self = this, symbol = self.symbol, ring = self.ring, field = ring.associatedField(), terms = self.terms, Arithmetic = Abacus.Arithmetic, coeffp, LCM, content, isReal, isImag; if (null == self._prim) { if (!terms.length) { self._prim = [self, field.One()]; } else if (is_class(ring.NumberClass, Complex)) { isReal = self.isReal(); isImag = self.isImag(); if (!isReal && !isImag) { content = ring.gcd(terms.map(function(t){return t.c;})).simpl(); self._prim = [Polynomial(terms.map(function(t){return UniPolyTerm(t.c.div(content), t.e, ring);}), symbol, ring), content]; } else if (isImag) { LCM = terms.reduce(function(LCM, t){return Arithmetic.mul(LCM, t.c.imag().den);}, Arithmetic.I); coeffp = terms.map(function(t){return t.c.mul(LCM).imag().num;}); content = gcd(coeffp); coeffp = coeffp.map(function(c){return Arithmetic.div(c, content);}); // make positive lead if (Arithmetic.gt(Arithmetic.O, coeffp[0])) { coeffp = coeffp.map(function(c){return Arithmetic.neg(c);}); content = Arithmetic.neg(content); } self._prim = [Polynomial(coeffp.map(function(c, i){return UniPolyTerm(c, terms[i].e, ring);}), symbol, ring), field.create(Complex.Img().mul(Rational(content, LCM).simpl()))]; } else { LCM = terms.reduce(function(LCM, t){return Arithmetic.mul(LCM, t.c.real().den);}, Arithmetic.I); coeffp = terms.map(function(t){return t.c.mul(LCM).real().num;}); content = gcd(coeffp); coeffp = coeffp.map(function(c){return Arithmetic.div(c, content);}); // make positive lead if (Arithmetic.gt(Arithmetic.O, coeffp[0])) { coeffp = coeffp.map(function(c){return Arithmetic.neg(c);}); content = Arithmetic.neg(content); } self._prim = [Polynomial(coeffp.map(function(c, i){return UniPolyTerm(c, terms[i].e, ring);}), symbol, ring), field.create(Rational(content, LCM).simpl())]; } } else { LCM = is_class(ring.NumberClass, Integer) ? Arithmetic.I : terms.reduce(function(LCM, t){return Arithmetic.mul(LCM, t.c.den);}, Arithmetic.I); coeffp = terms.map(function(t){return t.c.mul(LCM).num;}); content = gcd(coeffp); coeffp = coeffp.map(function(c){return Arithmetic.div(c, content);}); // make positive lead if (Arithmetic.gt(Arithmetic.O, coeffp[0])) { coeffp = coeffp.map(function(c){return Arithmetic.neg(c);}); content = Arithmetic.neg(content); } self._prim = [Polynomial(coeffp.map(function(c, i){return UniPolyTerm(c, terms[i].e, ring);}), symbol, ring), field.create(Rational(content, LCM).simpl())]; } } return true===and_content ? self._prim.slice() : self._prim[0]; } ,content: function() { var p = this.primitive(true); return p[1]; } ,roots: function() { // find all rational roots, if any // https://en.wikipedia.org/wiki/Rational_root_theorem // https://en.wikipedia.org/wiki/Gauss%27s_lemma_(polynomial) var self = this, ring = self.ring, Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, roots, primitive, c, p, d0, dn, iter, comb, root, nroot, rm, nrm, found; if (null == self._roots) { roots = []; // no rational roots or infinite roots for constant polynomials, // no rational roots for strictly complex polynomials if (!self.isConst() && (self.isImag() || self.isReal())) { primitive = self.primitive(); c = primitive.terms; if (0=0; i--) if (!t[i].equ(tp[i])) return false; return true; } else if (is_instance(p, [MultiPolynomial, RationalFunc])) { return p.equ(self); } else if (is_instance(p, [SymbolTerm, PowTerm, MulTerm])) { if (is_instance(p, [SymbolTerm, PowTerm])) p = MulTerm(p); if (1 < t.length) return false; else if (0 === t.length) return p.c().equ(O); s = t[0].toTerm(self.symbol); if (!s.length) s = '1'; return (s === p.symbol) && p.c().equ(t[0].c); } else if (is_instance(p, Expr)) { return self.toExpr().equ(p); } else if (is_string(p)) { return (p === self.toString()) || (p === self.toTex()); } return false; } ,gt: function(a) { var self = this, Arithmetic = Abacus.Arithmetic; if (is_instance(a, Numeric) || Arithmetic.isNumber(a)) { return !self.isConst() || self.cc().gt(a); } else if (is_instance(a, Polynomial)) { return 0UniPolyTerm.cmp(self.ltm(), a.ltm(), true); } else if (is_instance(a, [RationalFunc, MultiPolynomial])) { return a.gt(self); } else if (is_instance(a, [Expr, MulTerm, PowTerm, SymbolTerm])) { return self.toExpr().lt(a); } return false; } ,lte: function(a) { var self = this, Arithmetic = Abacus.Arithmetic; if (is_instance(a, Numeric) || Arithmetic.isNumber(a)) { return self.isConst() && self.cc().lte(a); } else if (is_instance(a, Polynomial)) { return 0>=UniPolyTerm.cmp(self.ltm(), a.ltm(), true); } else if (is_instance(a, [RationalFunc, MultiPolynomial])) { return a.gte(self); } else if (is_instance(a, [Expr, MulTerm, PowTerm, SymbolTerm])) { return self.toExpr().lte(a); } return false; } ,real: function() { var self = this, ring = self.ring; if (is_class(ring.NumberClass, Complex)) { return Polynomial(self.terms.map(function(t){ return UniPolyTerm(t.c.real(), t.e, ring); }), self.symbol, ring); } else { return self; } } ,imag: function() { var self = this, ring = self.ring; if (is_class(ring.NumberClass, Complex)) { return Polynomial(self.terms.map(function(t){ return UniPolyTerm(t.c.imag(), t.e, ring); }), self.symbol, ring); } else { return Polynomial([], self.symbol, ring); } } ,abs: function() { var self = this; return self.lc().lt(Abacus.Arithmetic.O) ? self.neg() : self; } ,conj: function() { var self = this, ring = self.ring; if (null == self._c) { if (is_class(ring.NumberClass, Complex)) { self._c = Polynomial(self.terms.map(function(t){ return UniPolyTerm(t.c.conj(), t.e, ring); }), self.symbol, ring); self._c._c = self; } else { self._c = self; } } return self._c; } ,neg: function() { var self = this, Arithmetic = Abacus.Arithmetic; if (null == self._n) { self._n = Polynomial(array(self.terms.length, function(i){return self.terms[i].neg();}), self.symbol, self.ring); self._n._n = self; } return self._n; } ,inv: NotImplemented ,add: function(x) { var self = this, Arithmetic = Abacus.Arithmetic; if (is_instance(x, [Expr, MulTerm, PowTerm, SymbolTerm])) return self.toExpr().add(x); else if (is_instance(x, [RationalFunc, MultiPolynomial])) return x.add(self); return Arithmetic.isNumber(x) || is_instance(x, [Numeric, Polynomial]) ? Polynomial.Add(x, self.clone()) : self; } ,sub: function(x) { var self = this, Arithmetic = Abacus.Arithmetic; if (is_instance(x, [Expr, MulTerm, PowTerm, SymbolTerm])) return self.toExpr().sub(x); else if (is_instance(x, [RationalFunc, MultiPolynomial])) return x.neg().add(self); return Arithmetic.isNumber(x) || is_instance(x, [Numeric, Polynomial]) ? Polynomial.Add(x, self.clone(), true) : self; } ,mul: function(x) { var self = this, Arithmetic = Abacus.Arithmetic; if (is_instance(x, [Expr, MulTerm, PowTerm, SymbolTerm])) return self.toExpr().mul(x); else if (is_instance(x, [RationalFunc, MultiPolynomial])) return x.mul(self); return Arithmetic.isNumber(x) || is_instance(x, [Numeric, Polynomial]) ? Polynomial.Mul(x, self.clone()) : self; } ,div: function(x, q_and_r) { var self = this; if (is_instance(x, RationalFunc)) return RationalFunc(MultiPolynomial(self, x.num.symbol, x.num.ring)).div(x); else if (is_instance(x, MultiPolynomial)) return MultiPolynomial(self, x.symbol, x.ring).div(x, q_and_r); return is_instance(x, [Polynomial, Numeric]) || Abacus.Arithmetic.isNumber(x) ? Polynomial.Div(self, x, true===q_and_r) : self; } ,multidiv: function(xs, q_and_r) { var self = this, p, qs, r, n, i, plt, xlt, t, divides, Arithmetic = Abacus.Arithmetic; q_and_r = (true===q_and_r); if (is_instance(xs, Polynomial)) xs = [xs]; if (!xs || !xs.length) return q_and_r ? [[], self] : []; n = xs.length; qs = array(n, function(){return [];}); r = []; p = self.clone(); while (p.terms.length/*!p.equ(Arithmetic.O)*/) { // Try to divide by a polynomial. plt = p.ltm(); divides = false; for (i=0; i>= 1; b = Polynomial.Mul(b, b); } return pow; } } ,rad: function(n) { var self = this, Arithmetic = Abacus.Arithmetic; n = Integer.cast(n); if (n.equ(Arithmetic.I)) return self; return polykthroot(self, n); } ,compose: function(q) { // functionaly compose one polynomial with another. ie result = P(Q(x)) var self = this, Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, pq, t, i, j; if (is_instance(q, MulTerm)) q = Expr(q); if (is_instance(q, Expr)) q = Polynomial.fromExpr(q, self.symbol, self.ring); if (Arithmetic.isNumber(q) || is_instance(q, Numeric)) { return Polynomial(self.evaluate(q), self.symbol, self.ring); } else if (is_instance(q, Polynomial)) { // Composition through variation of Horner's algorithm for fast evaluation // also check http://andy.novocin.com/pro/polycomp_CASC2011.pdf if (!self.terms.length) return Polynomial.Zero(q.symbol, self.ring); if (0 === self.deg()) return Polynomial(self.terms.slice(), q.symbol, self.ring); if (0 === q.deg()) return Polynomial(self.evaluate(q.cc()), q.symbol, self.ring); t = self.terms; i = t[0].e; pq = Polynomial(t[0].c, q.symbol, self.ring); j = 1; while (0 equivalent to multiplication/division by a monomial x^s var self = this, Arithmetic = Abacus.Arithmetic; s = Arithmetic.val(s); if (0 === s) return self; else if (0 > s) // division by monomial x^|s| return Polynomial(self.terms.map(function(term){ return term.e < -s ? null : UniPolyTerm(term.c, term.e+s, self.ring); }).filter(UniPolyTerm.isNonZero), self.symbol, self.ring); //else if (0 < s) // multiplication by monomial x^s return Polynomial(self.terms.map(function(term){ return UniPolyTerm(term.c, term.e+s, self.ring); }), self.symbol, self.ring); } ,d: function(n) { // polynomial (formal) derivative of nth order var self = this, Arithmetic = Abacus.Arithmetic, O = Arithmetic.O; if (null == n) n = 1; n = +n; if (0 > n) return null; // not supported else if (0 === n) return self; if (0 === self.terms.length) return self; return n >= self.terms[0].e ? Polynomial.Zero(self.symbol, self.ring) : Polynomial(self.terms.map(function(term){ if (n > term.e) return null; for (var c=Arithmetic.I,j=term.e; j+n>term.e; j--) c = Arithmetic.mul(c, j); return UniPolyTerm(term.c.mul(c), term.e-n, self.ring); }).filter(UniPolyTerm.isNonZero), self.symbol, self.ring); } ,polarForm: function(u) { // http://graphics.stanford.edu/courses/cs164-09-spring/Handouts/handout19.pdf // http://resources.mpi-inf.mpg.de/departments/d4/teaching/ss2010/geomod/slides_public/08_Blossoming_Polars.pdf u = String(u||'u'); var self = this, ring = self.ring.associatedField(), n = self.deg(), symbol = array(n, function(i){return u+'_'+(i+1);}); return self.terms.reduce(function(polar, term){ if (!term.e) return polar; var combinations = Combination(n, term.e), k = combinations.total(); return combinations.get().reduce(function(polar, comb){ return polar.add(MultiPolynomial(MultiPolyTerm(ring.cast(term.c).div(k), array(n, function(i){return -1 === comb.indexOf(i) ? 0 : 1;})), symbol, ring)); }, polar); }, MultiPolynomial(MultiPolyTerm(self.cc(), array(n, 0)), symbol, ring)); } ,evaluate: function(x) { // Horner's algorithm for fast evaluation // https://en.wikipedia.org/wiki/Horner%27s_method var self = this, ring = self.ring, Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, t = self.terms, i, j, v; if (!t.length) return ring.Zero(); if (!is_instance(x, Numeric) && !Arithmetic.isNumber(x) && is_obj(x)) x = x[self.symbol]; x = x || O; //x = ring.cast(x); i = t[0].e; v = t[0].c; j = 1; while (0=0; i--) { term = t[i].toTerm(x, false, true); terms.push(MulTerm(term.length ? term : '1', t[i].c)); } if (!terms.length) terms.push(MulTerm(1, O)); self._expr = Expr(terms); } return self._expr; } }); Polynomial.cast = function(a, symbol, ring) { ring = ring || Ring.Q(); symbol = String(symbol || 'x'); var type_cast = typecast(function(a){ return is_instance(a, Polynomial) && (a.ring===ring); }, function(a){ return is_string(a) ? Polynomial.fromString(a, symbol, ring) : new Polynomial(a, symbol, ring); }); return type_cast(a); }; // Represents a multivariate polynomial term with coefficient and exponents in Polynomial non-zero sparse representation MultiPolyTerm = Class({ constructor: function MultiPolyTerm(c, e, ring) { var self = this; if (!is_instance(self, MultiPolyTerm)) return new MultiPolyTerm(c, e, ring); if (is_instance(c, MultiPolyTerm)){ring = ring || c.ring; e = c.e.slice(); c = c.c;} else if (is_instance(c, UniPolyTerm)){ring = ring || c.ring; e = [c.e]; c = c.c;} self.ring = is_instance(ring, Ring) ? ring : Ring.Q(); if (is_instance(c, MultiPolynomial) && (c.ring.NumberClass!==self.ring.NumberClass) && !is_class(c.ring.NumberClass, Complex) && is_class(c.ring.NumberClass, [Integer, Rational]) && is_class(self.ring.NumberClass, [Rational, Complex])) { c = MultiPolynomial(c, c.symbol, self.ring); } self.c = is_instance(c, [MultiPolynomial, RationalFunc, RationalExpr]) ? c : self.ring.cast(c||0); self.e = is_array(e) ? e : [+(e||0)]; } ,__static__: { isNonZero: function(t) { return is_instance(t, MultiPolyTerm) && !t.c.equ(Abacus.Arithmetic.O); } ,cmp: function(t1, t2, full) { function cmp_exp_i(e1, e2, i) { if (i >= e1.length && i >= e2.length) return 0; else if (i >= e2.length) return 0===e1[i] ? cmp_exp_i(e1, e2, i+1) : e1[i]; else if (i >= e1.length) return 0===e2[i] ? cmp_exp_i(e1, e2, i+1) : -e2[i]; else if (e1[i]===e2[i]) return cmp_exp_i(e1, e2, i+1); return e1[i]-e2[i]; }; if ((is_array(t1)||is_args(t1)) && (is_array(t2)||is_args(t2))) return cmp_exp_i(t1, t2, 0); var res = cmp_exp_i(t1.e, t2.e, 0); if ((true===full) && (0===res)) return t1.c.equ(t2.c) ? 0 : (t1.c.lt(t2.c) ? -1 : 1); return res; } ,sortDecr: function(t1, t2) { return MultiPolyTerm.cmp(t2, t1); } ,gcd: function(t1, t2, full) { return MultiPolyTerm(true===full ? (!(is_instance(t1.c, [MultiPolynomial, RationalFunc, RationalExpr]) || is_instance(t2.c, [MultiPolynomial, RationalFunc, RationalExpr])) && t1.ring.hasGCD() ? t1.ring.gcd(t1.c, t2.c) : t1.ring.One()) : t1.ring.One(), array(stdMath.max(t1.e.length, t2.e.length), function(i){ return i= e1.length) { break; } else if (i >= e2.length) { if (0 < e1[i]) return false; } else if (e1[i] > e2[i]) { return false; } } return true; } ,pow: function(k) { var self = this; k = +k; return 1===k ? self : MultiPolyTerm(self.c.pow(k), array(self.e.length, function(i){return stdMath.floor(self.e[i]*k);}), self.ring); } ,rad: function(k) { var self = this; k = +k; return 1===k ? self : MultiPolyTerm(self.c.rad(k), array(self.e.length, function(i){return stdMath.max(stdMath.floor(self.e[i]/k), stdMath.min(1, self.e[i]));}), self.ring); } ,toTerm: function(symbol, asTex, monomialOnly, asDec, precision) { var t = this, e = t.e, c = t.c, term, Arithmetic = Abacus.Arithmetic; if (true===asDec) { term = symbol.reduce(function(monom, sym, i){ return 0 < e[i] ? (monom + (monom.length ? '*' : '') + sym + (1=0; i--) P.terms[i] = P.terms[i].mul(x); } } return P; } ,Div: function(P, x, q_and_r, recur) { var Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, I = Arithmetic.I, rsym, q/*, r, d, diff, diff0*/; q_and_r = (true===q_and_r); if (is_instance(x, Polynomial)) x = MultiPolynomial(x, P.symbol, P.ring); if (is_instance(x, MultiPolynomial)) { if (!x.terms.length) throw new Error('Division by zero in Abacus.MultiPolynomial!'); recur = (true===recur); if (recur) x = x.recur(false); // convert to flat representation if (x.isConst()) { // constant polynomial, simple numeric division x = x.cc(); q = x.equ(I) ? P : MultiPolynomial(array(P.terms.length, function(i){ return P.terms[i].div(x); }), P.symbol, P.ring); return q_and_r ? [q, MultiPolynomial.Zero(P.symbol, P.ring)] : q; } // sparse polynomial reduction/long division if (recur) { rsym = P._rsym; P = P.recur(false); } q = division_sparse(P.terms, x.terms, MultiPolyTerm, q_and_r, P.ring); q = q_and_r ? [MultiPolynomial(q[0], P.symbol, P.ring), MultiPolynomial(q[1], P.symbol, P.ring)] : MultiPolynomial(q, P.symbol, P.ring); if (recur && rsym) { if (q_and_r) { q[0] = q[0].recur(rsym); q[1] = q[1].recur(rsym); } else q = q.recur(rsym); } return q; } else if (is_instance(x, Numeric) || Arithmetic.isNumber(x)) { /*if (Arithmetic.isNumber(x))*/ x = P.ring.cast(x); if (x.equ(O)) throw new Error('Division by zero in Abacus.MultiPolynomial!'); q = x.equ(I) ? P : MultiPolynomial(array(P.terms.length, function(i){ return P.terms[i].div(x); }), P.symbol, P.ring); return q_and_r ? [q, MultiPolynomial.Zero(P.symbol, P.ring)] : q; } return P; } ,C: function(c, x, ring) { return new MultiPolynomial(c || Abacus.Arithmetic.O, x||['x'], ring||Ring.Q()); } ,fromExpr: function(e, x, ring) { if (!is_instance(e, Expr)) return null; ring = ring || Ring.Q(); x = x || ['x']; var symbols = e.symbols(), i, s, tc, O = Abacus.Arithmetic.O, terms = {}; for (i=symbols.length-1; i>=0; i--) { s = symbols[i]; tc = e.terms[s].c(); if (tc.equ(O)) continue; terms[s] = tc; } return new MultiPolynomial(terms, x, ring); } ,fromString: function(s, symbol, ring) { var Arithmetic = Abacus.Arithmetic, terms = {}, m, mm, coeff, sym, found_symbols = [], n, i, term_re = /(\(?(?:(?:[\+\-])?\s*\(?(?:(?:\\frac\{\-?\d+\}\{\-?\d+\})|(?:\-?\d+(?:\.\d*(?:\[\d+\])?)?(?:e-?\d+)?(?:\/\-?\d+)?))?\)?)(?:\s*(?:[\+\-])?\s*(?:\(?(?:(?:\\frac\{\-?\d+\}\{\-?\d+\})|(?:\-?\d+(?:\.\d*(?:\[\d+\])?)?(?:e-?\d+)?(?:\/\-?\d+)?))\)?\*?)?(?:[ij]))?\)?)?(?:\s*\*?\s*([a-zA-Z](?:_\{?\d+\}?)?(?:\^\{?\d+\}?)?(?:\s*\*?\s*[a-zA-Z](?:_\{?\d+\}?)?(?:\^\{?\d+\}?)?)*)?)?/g, monomial_re = /([a-zA-Z])(?:_\{?(\d+)\}?)?(?:\^\{?(\d+)\}?)?/g, monomials, ms, me, term; ring = ring || Ring.Q(); s = trim(String(s)); if (!s.length) return MultiPolynomial.Zero(symbol||['x'], ring); while ((m=term_re.exec(s))) { // try to do best possible match of given string of expressionl terms if (!m[0].length) { if (term_re.lastIndex < s.length) { term_re.lastIndex++; continue; } else { break; // match at least sth } } if (!trim(m[0]).length) continue; // matched only spaces, continue if (m[2]) { sym = m[2]; coeff = trim(m[1] || ''); if (('' === coeff) || ('+' === coeff) ) coeff = '1'; else if ('-' === coeff) coeff = '-1'; monomials = {}; // split each monomial symbol from combined term while ((mm=monomial_re.exec(sym))) { ms = mm[1]+(mm[2]?('_'+mm[2]):''); me = mm[3] ? parseInt(mm[3], 10) : 1; if (0 === me) { monomials['1'] = 0; } else { if (symbol && (-1===symbol.indexOf(ms))) continue; if (!symbol && (-1===found_symbols.indexOf(ms))) found_symbols.push(ms); monomials[ms] = HAS.call(monomials, ms) ? (monomials[ms]+me) : me; } } if (HAS.call(monomials, '1') && (1=0; i--) if (!terms[i].c.isInt()) return false; return true; } ,isReal: function() { // has real coefficients var self = this, terms = self.terms, i; if (!is_class(self.ring.NumberClass, Complex)) return true; for (i=terms.length-1; i>=0; i--) if (!terms[i].c.isReal()) return false; return true; } ,isImag: function() { // has imaginary coefficients var self = this, terms = self.terms, i; if (!is_class(self.ring.NumberClass, Complex)) return false; for (i=terms.length-1; i>=0; i--) if (!terms[i].c.isImag()) return false; return true; } ,isMono: function() { // is monomial var terms = this.terms; return (1===terms.length) && ((!is_instance(terms[0].c, MultiPolynomial) || terms[0].c.isMono()) && 0!==MultiPolyTerm.cmp(terms[0].e, [0])); } ,isConst: function(recur) { var terms = this.terms; recur = (true===recur); return (0===terms.length) || ((1===terms.length) && ((!recur || !is_instance(terms[0].c, MultiPolynomial) || terms[0].c.isConst(recur)) && 0===MultiPolyTerm.cmp(terms[0].e, [0]))); } ,isUni: function(x, strict) { // is univariate on symbol x var self = this, terms = self.terms, index, e, i, d; index = self.symbol.indexOf(String(x||'x')); if (-1 === index) return false; strict = (true===strict); d = 0; for (i=terms.length-1; i>=0; i--) { e = terms[i].e; d = stdMath.max(d, e[index]); if (0!==MultiPolyTerm.cmp(e.slice(0, index).concat(e.slice(index+1)), [0])) return false; } return strict ? (0!==d) : true; } ,isRecur: function(strict) { // is recursive, has coefficients that are multipolynomials on rest variables //return (null!=this._rsym) && (0=0; i--) if (is_instance(terms[i].c, MultiPolynomial) && (strict || !terms[i].c.isConst(true))) return true; return false; } ,deg: function(x, recur) { // polynomial degree var self = this, terms = self.terms, symbol = self.symbol, index; if (arguments.length) { recur = (true===recur); index = symbol.indexOf(String(x||'x')); return (-1 === index) || !terms.length ? 0 : (recur && is_instance(term[0].c, MultiPolynomial) ? (terms[0].e[index]+term[0].c.deg(x, recur)) : terms[0].e[index]); } return terms.length ? terms[0].e : array(symbol.length, 0); } ,maxdeg: function(x, recur) { // polynomial maximum degree per symbol var self = this, terms = self.terms, symbol = self.symbol, index; recur = (true===recur); if (arguments.length && (true===x)) { return operate(function(max, xi){ return stdMath.max(max, self.maxdeg(xi)); }, 0, symbol); } index = arguments.length ? symbol.indexOf(String(x||'x')) : 0; if ((-1 === index) || !terms.length) return 0; x = symbol[index]; return operate(function(max, t){ if (recur && is_instance(t.c, MultiPolynomial)) return stdMath.max(max, t.e[index], t.e[index]+t.c.maxdeg(x, recur)); else return stdMath.max(max, t.e[index]); }, 0, terms); } ,mindeg: function(x, recur) { // polynomial minimum degree per symbol var self = this, terms = self.terms, symbol = self.symbol, index; recur = (true===recur); if (arguments.length && (true===x)) { return operate(function(min, xi){ return -1 === min ? self.mindeg(xi, recur) : stdMath.min(min, self.mindeg(xi, recur)); }, -1, symbol); } index = arguments.length ? symbol.indexOf(String(x||'x')) : 0; if ((-1 === index) || !terms.length) return 0; x = symbol[index]; return operate(function(min, t){ var deg = t.e[index]+(recur && is_instance(t.c, MultiPolynomial) ? t.c.mindeg(x, recur) : 0); return -1===min ? deg : stdMath.min(min, deg); }, -1, terms); } ,term: function(i, as_degree) { // term(s) matching i as index or as degree var self = this, terms = self.terms, ring = self.ring, symbol = self.symbol; if (true===as_degree) return terms.reduce(function(matched, t){ // amtch all terms which have i as aggregate degree if (i===t.e.reduce(addn, 0)) matched = matched.add(MultiPolynomial([t], symbol, ring)); return matched; }, MultiPolynomial.Zero(symbol, ring)); return MultiPolynomial(0<=i && i t.e[index])) min = t; return min; }, null, terms); return true===asPoly ? MultiPolynomial([term], symbol, ring) : term; } if (true===asPoly) return MultiPolynomial(terms.length ? [terms[terms.length-1]] : [], symbol, ring); return terms.length ? terms[terms.length-1] : MultiPolyTerm(0, array(symbol.length, 0), ring); } ,lm: function(x) { // leading monomial (per symbol) var self = this, lt = arguments.length ? self.ltm(false, x) : self.ltm(false); return lt.e; } ,lc: function(x) { // leading coefficient (per symbol) var self = this, lt = arguments.length ? self.ltm(false, x) : self.ltm(false); return lt.c; } ,tm: function(x) { // tail monomial (per symbol) var self = this, tt = arguments.length ? self.ttm(false, x) : self.ttm(false); return tt.e; } ,tc: function(x) { // tail coefficient (per symbol) var self = this, tt = arguments.length ? self.ttm(false, x) : self.ttm(false); return tt.c; } ,cc: function() { // constant coefficient var terms = this.terms; return terms.length && (0===MultiPolyTerm.cmp(terms[terms.length-1].e, [0])) ? terms[terms.length-1].c : this.ring.Zero(); } ,c: function() { // alias of cc() return this.cc(); } ,recur: function(x) { var self = this, terms = self.terms, symbol = self.symbol, ring = self.ring, Arithmetic = Abacus.Arithmetic, index, maxdeg, pr, c = null; if (false === x) { // make non-recursive if (null == self._flat) { self._flat = (1 >= symbol.length) || !self.isRecur() ? self : operate(function(p, t){ return p._add(is_instance(t.c, MultiPolynomial) ? MultiPolynomial([MultiPolyTerm(ring.One(), t.e, ring)], symbol, ring)._mul(t.c.recur(false)) : MultiPolynomial([t], symbol, ring)); }, MultiPolynomial.Zero(symbol, ring), terms); self._flat._rsym = null; self._flat._flat = self._flat; } return self._flat; } else if (true === x) { // make recursive on all variables succesively if (null == self._recur) { self._recur = 1 >= symbol.length ? self : operate(function(p, x){return p.recur(x);}, self.recur(false), symbol); self._recur._flat = self.recur(false); self._recur._recur = self._recur; } return self._recur; } else if (is_array(x)) { return operate(function(p, xi){return p.recur(xi);}, self, x); } else if (x) { // make recursive on/group by symbol x // idempotent if is already grouped on x if (1 >= symbol.length) return self; x = String(x||'x'); index = symbol.indexOf(x); if ((-1 === index) || (self._rsym && (-1 !== self._rsym.indexOf(x)))) return self; /*if (self.isUni(x)) { self._rsym = (self._rsym||[]).concat(x); return self; }*/ maxdeg = self.maxdeg(x, true) if (0 === maxdeg) { self._rsym = (self._rsym||[]).concat(x); return self; } pr = MultiPolynomial(operate(function(terms, t){ var e = t.e[index], i = maxdeg-e, tt, p; if (is_instance(t.c, MultiPolynomial)) { /*if ((0 < e) && (0 < t.c.maxdeg(x, true))) { // messed up, try to regroup tt = t.clone(); tt.e[index] = 0; tt.c = t.c.mul(MultiPolynomial([t], symbol, ring)).recur(x); p = MultiPolynomial([tt], symbol, ring); } else */if (t.c.isUni(x)) { // recursive on same p = MultiPolynomial([t], symbol, ring); } else { // recursive on other tt = t.clone(); tt.c = t.c.recur(x); tt.e[index] = 0; p = MultiPolynomial([tt], symbol, ring); } } else if (0 !== e) { tt = t.clone(); tt.e[index] = 0; p = MultiPolynomial([tt], symbol, ring); } else { p = MultiPolynomial([t], symbol, ring); } // group by same power/exponent of recursive symbol // put them directly in reverse order to avoid reversing later on terms[i] = terms[i] ? terms[i]._add(p) : p; return terms; }, new Array(maxdeg+1), terms).map(function(t, e){ return t.equ(Arithmetic.O) ? null : MultiPolyTerm(t, array(symbol.length, function(i){return index===i ? maxdeg-e : 0;})); }).filter(MultiPolyTerm.isNonZero), symbol, ring); while (pr.isConst() && is_instance(c=pr.cc(), MultiPolynomial)) pr = c; if (c === pr) pr = pr.clone(); // copy it to avoid mutating existing poly pr._rsym = (self._rsym||[]).concat(x); return pr; } return self; } ,monic: function() { var self = this, Arithmetic = Abacus.Arithmetic, lc = self.lc(), i, t, divides; if (lc.equ(Arithmetic.I) || lc.equ(Arithmetic.O) || is_instance(lc, MultiPolynomial)) return self; if (self.ring.isField()) { return MultiPolynomial(self.terms.map(function(t){return t.div(lc);}), self.symbol, self.ring); } else { divides = true; t = self.terms; for (i=t.length-1; i>0; i--) { if (!lc.divides(t[i].c)) { divides = false; break; } } // at least make positive return divides ? MultiPolynomial(self.terms.map(function(t){return t.div(lc);}), self.symbol, self.ring) : (lc.lt(Arithmetic.O) ? self.neg() : self); } } ,primitive: function(and_content) { // factorise into content and primitive part // https://en.wikipedia.org/wiki/Factorization_of_polynomials#Primitive_part%E2%80%93content_factorization var self = this, symbol = self.symbol, ring = self.ring, field = ring.associatedField(), terms = self.terms, Arithmetic = Abacus.Arithmetic, coeffp, LCM, content, isReal, isImag; if (null == self._prim) { if (!terms.length) { self._prim = [self, field.One()]; } else if (self.isRecur()) { coeffp = terms.reduce(function(coeffp, t){ coeffp.push(is_instance(t.c, MultiPolynomial) ? t.c.primitive(true) : [MultiPolynomial([t], symbol, ring), field.One()]); return coeffp; }, []); content = field.gcd(coeffp.map(function(c){return c[1];})); self._prim = [MultiPolynomial(coeffp.map(function(c, i){ return MultiPolyTerm(c[0].mul(ring.cast(c[1].div(content))), terms[i].e, ring); }), symbol, ring), content]; } else if (is_class(ring.NumberClass, Complex)) { isReal = self.isReal(); isImag = self.isImag(); if (!isReal && !isImag) { content = ring.gcd(terms.map(function(t){return t.c;})).simpl(); self._prim = [MultiPolynomial(terms.map(function(t){return MultiPolyTerm(t.c.div(content), t.e, ring);}), symbol, ring), content]; } else if (isImag) { LCM = terms.reduce(function(LCM, t){return Arithmetic.mul(LCM, t.c.imag().den);}, Arithmetic.I); coeffp = terms.map(function(t){return t.c.mul(LCM).imag().num;}); content = gcd(coeffp); coeffp = coeffp.map(function(c){return Arithmetic.div(c, content);}); // make positive lead if (Arithmetic.gt(Arithmetic.O, coeffp[0])) { coeffp = coeffp.map(function(c){return Arithmetic.neg(c);}); content = Arithmetic.neg(content); } self._prim = [MultiPolynomial(coeffp.map(function(c, i){return MultiPolyTerm(c, terms[i].e, ring);}), symbol, ring), field.create(Complex.Img().mul(Rational(content, LCM).simpl()))]; } else { LCM = terms.reduce(function(LCM, t){return Arithmetic.mul(LCM, t.c.real().den);}, Arithmetic.I); coeffp = terms.map(function(t){return t.c.mul(LCM).real().num;}); content = gcd(coeffp); coeffp = coeffp.map(function(c){return Arithmetic.div(c, content);}); // make positive lead if (Arithmetic.gt(Arithmetic.O, coeffp[0])) { coeffp = coeffp.map(function(c){return Arithmetic.neg(c);}); content = Arithmetic.neg(content); } self._prim = [MultiPolynomial(coeffp.map(function(c, i){return MultiPolyTerm(c, terms[i].e, ring);}), symbol, ring), field.create(Rational(content, LCM).simpl())]; } } else { LCM = is_class(ring.NumberClass, Integer) ? Arithmetic.I : terms.reduce(function(LCM, t){return Arithmetic.mul(LCM, t.c.den);}, Arithmetic.I); coeffp = terms.map(function(t){return t.c.mul(LCM).num;}); content = gcd(coeffp); coeffp = coeffp.map(function(c){return Arithmetic.div(c, content);}); // make positive lead if (Arithmetic.gt(Arithmetic.O, coeffp[0])) { coeffp = coeffp.map(function(c){return Arithmetic.neg(c);}); content = Arithmetic.neg(content); } self._prim = [MultiPolynomial(coeffp.map(function(c, i){return MultiPolyTerm(c, terms[i].e, ring);}), symbol, ring), field.create(Rational(content, LCM).simpl())]; } } return true===and_content ? self._prim.slice() : self._prim[0]; } ,content: function() { var p = this.primitive(true); return p[1]; } ,equ: function(p, strict) { var self = this, Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, t = self.terms, tp, s, i; if (Arithmetic.isNumber(p)) { return Arithmetic.equ(O, p) ? 0===t.length : ((1===t.length) && t[0].c.equ(p) && (0===MultiPolyTerm.cmp(t[0].e, [0]))); } else if (is_instance(p, Numeric)) { return p.equ(O) ? 0===t.length : ((1===t.length) && t[0].c.equ(p) && (0===MultiPolyTerm.cmp(t[0].e, [0]))); } else if (is_instance(p, Poly)) { strict = (false!==strict); p = is_instance(p, Polynomial) ? MultiPolynomial(p, self.symbol, self.ring).terms : p; if (!strict) { t = self.recur(false).terms; p = p.recur(false); } tp = p.terms; if (t.length !== tp.length) return false; for (i=t.length-1; i>=0; i--) if (!t[i].equ(tp[i])) return false; return true; } else if (is_instance(p, RationalFunc)) { return p.equ(self); } else if (is_instance(p, [SymbolTerm, PowTerm, MulTerm])) { if (is_instance(p, [SymbolTerm, PowTerm])) p = MulTerm(p); if (1 < t.length) return false; else if (0 === t.length) return p.c().equ(O); s = t[0].toTerm(self.symbol); if (!s.length) s = '1'; return (s === p.symbol) && p.c().equ(t[0].c); } else if (is_instance(p, Expr)) { return self.toExpr().equ(p); } else if (is_string(p)) { return (p === self.toString()) || (p === self.toTex()); } return false; } ,gt: function(a) { var self = this, Arithmetic = Abacus.Arithmetic; if (is_instance(a, Numeric) || Arithmetic.isNumber(a)) { return !self.isConst(true) || self.cc().gt(a); } else if (is_instance(a, RationalFunc)) { return a.lt(self); } else if (is_instance(a, Poly)) { if (is_instance(a, Polynomial)) a = MultiPolynomial(a, self.symbol, self.ring); return 0MultiPolyTerm.cmp(self.ltm(), a.ltm(), true); } else if (is_instance(a, [Expr, MulTerm, PowTerm, SymbolTerm])) { return self.toExpr().lt(a); } return false; } ,lte: function(a) { var self = this, Arithmetic = Abacus.Arithmetic; if (is_instance(a, Numeric) || Arithmetic.isNumber(a)) { return self.isConst(true) && self.cc().lte(a); } else if (is_instance(a, RationalFunc)) { return a.gte(self); } else if (is_instance(a, Poly)) { if (is_instance(a, Polynomial)) a = MultiPolynomial(a, self.symbol, self.ring); return 0>=MultiPolyTerm.cmp(self.ltm(), a.ltm(), true); } else if (is_instance(a, [Expr, MulTerm, PowTerm, SymbolTerm])) { return self.toExpr().lte(a); } return false; } ,real: function() { var self = this, ring = self.ring; if (is_class(ring.NumberClass, Complex)) { return MultiPolynomial(self.terms.map(function(t){ return MultiPolyTerm(t.c.real(), t.e, ring); }), self.symbol, ring); } else { return self; } } ,imag: function() { var self = this, ring = self.ring; if (is_class(ring.NumberClass, Complex)) { return MultiPolynomial(self.terms.map(function(t){ return MultiPolyTerm(t.c.imag(), t.e, ring); }), self.symbol, ring); } else { return MultiPolynomial([], self.symbol, ring); } } ,abs: function() { var self = this; return self.lc().lt(Abacus.Arithmetic.O) ? self.neg() : self; } ,conj: function() { var self = this, ring = self.ring; if (null == self._c) { if (is_class(ring.NumberClass, Complex)) { self._c = MultiPolynomial(self.terms.map(function(t){ return MultiPolyTerm(t.c.conj(), t.e, ring); }), self.symbol, ring); self._c._c = self; } else { self._c = self; } } return self._c; } ,neg: function() { var self = this, Arithmetic = Abacus.Arithmetic; if (null == self._n) { self._n = MultiPolynomial(array(self.terms.length, function(i){return self.terms[i].neg();}), self.symbol, self.ring); self._n._n = self; } return self._n; } ,inv: NotImplemented ,add: function(x) { var self = this, Arithmetic = Abacus.Arithmetic; if (is_instance(x, [Expr, MulTerm, PowTerm, SymbolTerm])) return self.toExpr().add(x); else if (is_instance(x, RationalFunc)) return x.add(self); return Arithmetic.isNumber(x) || is_instance(x, [Numeric, Poly]) ? MultiPolynomial.Add(x, self.clone(), false, true) : self; } ,_add: function(x) { // add as is without preserving any recursive representation var self = this; return is_instance(x, Poly) ? MultiPolynomial.Add(x, self.clone(), false, false) : self.add(x); } ,sub: function(x) { var self = this, Arithmetic = Abacus.Arithmetic; if (is_instance(x, [Expr, MulTerm, PowTerm, SymbolTerm])) return self.toExpr().sub(x); else if (is_instance(x, RationalFunc)) return x.neg().add(self); return Arithmetic.isNumber(x) || is_instance(x, [Numeric, Poly]) ? MultiPolynomial.Add(x, self.clone(), true, true) : self; } ,_sub: function(x) { // sub as is without preserving any recursive representation var self = this; return is_instance(x, Poly) ? MultiPolynomial.Add(x, self.clone(), true, false) : self.sub(x); } ,mul: function(x) { var self = this, Arithmetic = Abacus.Arithmetic; if (is_instance(x, [Expr, MulTerm, PowTerm, SymbolTerm])) return self.toExpr().mul(x); else if (is_instance(x, RationalFunc)) return x.mul(self); return Arithmetic.isNumber(x) || is_instance(x, [Numeric, Poly]) ? MultiPolynomial.Mul(x, self.clone(), true) : self; } ,_mul: function(x) { // mul as is without preserving any recursive representation var self = this; return is_instance(x, Poly) ? MultiPolynomial.Mul(x, self.clone(), false) : self.mul(x); } ,div: function(x, q_and_r) { var self = this; if (is_instance(x, RationalFunc)) return RationalFunc(self).div(x); else if (is_instance(x, [Numeric, Poly]) || Abacus.Arithmetic.isNumber(x)) return MultiPolynomial.Div(self, x, true===q_and_r, true); return self; } ,_div: function(x, q_and_r) { // div as is without preserving any recursive representation var self = this; return is_instance(x, Poly) ? MultiPolynomial.Div(self, x, true===q_and_r, false) : self.div(x, q_and_r); } ,multidiv: function(xs, q_and_r) { var self = this, p, qs, r, n, i, plt, xlt, t, divides, rsym = self._rsym, Arithmetic = Abacus.Arithmetic; q_and_r = (true===q_and_r); if (is_instance(xs, MultiPolynomial)) xs = [xs]; if (!xs || !xs.length) return q_and_r ? [[], self] : []; n = xs.length; qs = array(n, function(){return [];}); r = []; p = self.recur(false).clone(); xs = xs.map(function(xi){return xi.recur(false);}); while (p.terms.length/*!p.equ(Arithmetic.O)*/) { // Try to divide by a polynomial. plt = p.ltm(); divides = false; for (i=0; i>= 1; b = MultiPolynomial.Mul(b, b, false); } if (rsym) pow = pow.recur(rsym); return pow; } } ,rad: function(n) { var self = this, Arithmetic = Abacus.Arithmetic; n = Integer.cast(n); if (n.equ(Arithmetic.I)) return self; return polykthroot(self, n); } ,compose: function(q) { // composition through variation on recursive Horner scheme var self = this, symbol = self.symbol, ring = self.ring, rsym = self._rsym, pq, Arithmetic = Abacus.Arithmetic, O = MultiPolynomial.Zero(symbol, ring), horner, memo = Obj(); horner = function horner(p, q, index) { index = index || 0; while ((index= symbol.length) return MultiPolynomial(p.cc(), symbol, ring); var s, t = p.terms, i, j, pq, qi, tc; if (!t.length) return O; // memoize, sometimes same subpolynomial is re-evaluated s = p.toString(); if (HAS.call(memo, s)) return memo[s]; qi = HAS.call(q, symbol[index]) ? MultiPolynomial(q[symbol[index]]||Arithmetic.O, symbol, ring) : MultiPolynomial([MultiPolyTerm(ring.One(), array(symbol.length, function(i){return i===index ? 1 : 0}), ring)], symbol, ring); tc = is_instance(t[0].c, MultiPolynomial) ? horner(t[0].c, q, index+1) : MultiPolynomial(t[0].c, symbol, ring); i = t[0].e[index]; pq = tc; j = 1; while (0 equivalent to multiplication/division by a monomial x^s var self = this, symbol = self.symbol, ring = self.ring, Arithmetic = Abacus.Arithmetic, index; x = String(x || symbol[0]); s = s || 0; index = symbol.indexOf(x); if (-1===index) index = 0; x = symbol[index]; s = Arithmetic.val(s); if (0 === s) return self; if (0 > s) // division by monomial x^|s| { if (-s > self.maxdeg(x, true)) return MultiPolynomial.Zero(symbol, ring); return MultiPolynomial(self.terms.map(function(term){ var k, e; term = term.clone(); if (is_instance(term.c, MultiPolynomial)) { e = term.e[index]; k = s; if (0 < e) { if (e >= -k) { term.e[index] += k; k = 0; } else { term.e[index] = 0; k += e; } } if (0 > k) term.c = term.c.shift(x, k); } else { if (term.e[index] >= -s) term.e[index] += s; else term.c = ring.Zero(); } return term; }).filter(MultiPolyTerm.isNonZero).sort(MultiPolyTerm.sortDecr), symbol, ring); } //else if (0 < s) // multiplication by monomial x^s return MultiPolynomial(self.terms.map(function(term){ term = term.clone(); if (is_instance(term.c, MultiPolynomial)) { if (0 < term.c.maxdeg(x, true)) term.c = term.c.shift(x, s); else term.e[index] += s; } else { term.e[index] += s; } return term; }).sort(MultiPolyTerm.sortDecr), symbol, ring); } ,d: function(x, n) { // partial polynomial (formal) derivative of nth order with respect to symbol x var self = this, symbol = self.symbol, ring = self.ring, dp, Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, I = Arithmetic.I, index; x = String(x || symbol[0]); if (null == n) n = 1; n = Arithmetic.val(n); if (0 > n) return null; // not supported else if (0 === n) return self; index = symbol.indexOf(x); if (-1===index) index = 0; x = symbol[index]; if (n > self.maxdeg(x, true)) return MultiPolynomial.Zero(symbol, ring); dp = MultiPolynomial(self.terms.map(function(term){ var c, j; if (is_instance(term.c, MultiPolynomial)) { if (term.c.isConst(true)) { if (n > term.e[index]) { return null; } else { term = term.clone(); for (c=I,j=term.e[index]; j+n>term.e[index]; j--) c = Arithmetic.mul(c, j); term.c = term.c._mul(c); term.e[index] -= n; return term; } } else { term = term.clone(); j = n; do{ j--; term.c = term.c.d(x,1)._add(term.c._mul(term.e[index])); term.e[index] = stdMath.max(term.e[index]-1, 0); }while ((0 < j) && !term.c.equ(O)) return term; } } else { if (n > term.e[index]) { return null; } else { term = term.clone(); for (c=I,j=term.e[index]; j+n>term.e[index]; j--) c = Arithmetic.mul(c, j); term.c = term.c.mul(c); term.e[index] -= n; return term; } } }).filter(MultiPolyTerm.isNonZero).sort(MultiPolyTerm.sortDecr), symbol, ring); return dp; } ,evaluate: function(x) { // recursive Horner scheme var self = this, symbol = self.symbol, ring = self.ring, O = Abacus.Arithmetic.O, horner, memo = Obj(); horner = function horner(p, x, index) { index = index || 0; while ((index= symbol.length) return p.cc(); var s, t = p.terms, i, j, v, xi, tc; if (!t.length) return ring.Zero(); // memoize, sometimes same subpolynomial is re-evaluated s = p.toString(); if (HAS.call(memo, s)) return memo[s]; xi = (HAS.call(x, symbol[index]) ? x[symbol[index]] : O) || O; //xi = ring.cast(xi); tc = is_instance(t[0].c, MultiPolynomial) ? horner(t[0].c, x, index+1) : t[0].c; i = t[0].e[index]; v = tc; j = 1; while (0=0; i--) { ti = t[i]; term = ti.toTerm(x, false, true); terms.push(MulTerm(term.length ? term : '1', ti.c)); } if (!terms.length) terms.push(MulTerm(1, O)); self._expr = Expr(terms); } } return self._expr; } }); MultiPolynomial.cast = function(a, symbol, ring) { ring = ring || Ring.Q(); symbol = symbol || 'x'; if (!is_array(symbol)) symbol = [String(symbol)]; var type_cast = typecast(function(a){ return is_instance(a, MultiPolynomial) && (a.ring===ring); }, function(a){ return is_string(a) ? MultiPolynomial.fromString(a, symbol, ring) : new MultiPolynomial(a, symbol, ring); }); return type_cast(a); }; // Abacus.RationalFunc, represents a rational function/fraction of (multivariate) polynomials RationalFunc = Abacus.RationalFunc = Class(Symbolic, { constructor: function RationalFunc(/*num, den, symbol, ring, simplified*/) { var self = this, Arithmetic = Abacus.Arithmetic, args = arguments, num, den, symbol, ring, simplified, simplify = RationalFunc.autoSimplify; simplified = (4=l) || ('/'===s.charAt(i)))) { if ((i n) { n = -n; t = num; num = den; den = t; } if (0 === n) return RationalFunc.One(num.symbol, num.ring); else if (1 === n) return RationalFunc(num, den, num.symbol, num.ring, self._simpl); else return RationalFunc(num.pow(n), den.pow(n), num.symbol, num.ring, self._simpl); } ,rad: function(n) { var self = this, Arithmetic = Abacus.Arithmetic; n = Integer.cast(n); if (n.equ(Arithmetic.I)) return self; return kthroot(self, n); } ,shift: function(x, s) { // shift <-> equivalent to multiplication/division by a monomial x^s var self = this, Arithmetic = Abacus.Arithmetic; x = String(x || self.num.symbol[0]); s = s || 0; s = Arithmetic.val(s); if (0 === s) return self; return 0 > s ? RationalFunc(self.num, self.den.shift(x, -s)) : RationalFunc(self.num.shift(x, s), self.den); } ,d: function(x, n) { // partial rational (formal) derivative of nth order with respect to symbol x var self = this, num, den, d_num, d_den, Arithmetic = Abacus.Arithmetic; x = String(x || self.num.symbol[0]); if (null == n) n = 1; n = Arithmetic.val(n); if (0 > n) return null; // not supported else if (0 === n) return self; num = self.num; den = self.den; while (0 args.length) args.push(null); return self.PolynomialClass.apply(null, args.concat([self.PolynomialSymbol, self.CoefficientRing])); } else if (self.PolynomialClass) { return self.PolynomialClass.apply(null, [args[0], self.PolynomialSymbol, self.CoefficientRing]); } return self.NumberClass.apply(null, self.Modulo ? [args[0], self.Modulo] : args); } ,fromString: function(s) { var self = this; s = trim(String(s)); return s.length ? (self.PolynomialClass ? self.PolynomialClass.fromString(s, self.PolynomialSymbol, self.CoefficientRing) : (is_class(self.NumberClass, [Expr, RationalExpr]) ? self.NumberClass.fromString(s) : self.NumberClass.fromString(s, self.Modulo))) : self.Zero(); } ,fromExpr: function(e) { var self = this; if (!is_instance(e, Expr)) return null; return self.PolynomialClass ? self.PolynomialClass.fromExpr(e, self.PolynomialSymbol, self.CoefficientRing) : self.cast(e.c()); } ,fromValues: function(v) { var self = this; return is_class(self.PolynomialClass, Polynomial) ? self.PolynomialClass.fromValues(v, self.PolynomialSymbol, self.CoefficientRing) : null; } ,toString: function() { var self = this; if (null == self._str) { self._str = (is_class(self.NumberClass, IntegerMod) ? 'Zn('+self.Modulo.toString()+')(' : (is_class(self.NumberClass, Integer) ? 'Z(' : (is_class(self.NumberClass, Rational) ? 'Q(' : 'C('))) + (self.PolynomialSymbol ? ('"'+[].concat(self.PolynomialSymbol).join('","')+'"') : '') + ')'; if (is_class(self.PolynomialClass, RationalFunc)) self._str += '.associatedField()'; } return self._str; } ,toTex: function() { var self = this; if (null == self._tex) { self._tex = '\\mathbb' + (is_class(self.NumberClass, IntegerMod) ? ('{Z}_{'+self.Modulo.toTex()+'}') : (is_class(self.NumberClass, Integer) ? '{Z}' : (is_class(self.NumberClass, Rational) ? '{Q}' : '{C}'))) + (self.PolynomialSymbol ? ('['+[].concat(self.PolynomialSymbol).map(to_tex).join(',')+']') : ''); if (is_class(self.PolynomialClass, RationalFunc)) self._tex = '\\mathbf{Fr}['+self._tex+']'; } return self._tex; } }); // Abacus.Matrix, represents a (2-dimensional) (dense) matrix with coefficients from a ring, default Ring.Z() Matrix = Abacus.Matrix = Class(INumber, { constructor: function Matrix(ring, r, c, values) { var self = this, k, v, i, j; if (!is_instance(self, Matrix)) return new Matrix(ring, r, c, values); if (!is_instance(ring, Ring)) ring = Ring.Z(); self.ring = ring; if (is_instance(r, Matrix)) { self.val = r.val.map(function(row){return row.slice()}); if (self.ring !== r.ring) self.val = self.ring.cast(self.val); } else if (is_array(r) || is_args(r)) { if (!is_array(r[0]) && !is_args(r[0])) { self.val = c ? /*row*/array(1, function(i){ return array(r.length, function(j){ return self.ring.cast(r[j]); }); }) : /*column*/array(r.length, function(i){ return array(1, function(j){ return self.ring.cast(r[i]); }); }); } else { if (is_args(r)) r = slice.call(r); if (is_args(r[0])) r = r.map(function(ri){return slice.call(ri);}); self.val = self.ring.cast(r); } } else //if (is_number(r) && is_number(c)) { if (null == c) c = r; // square r = (+(r||0))|0; c = (+(c||0))|0; if (0>r) r = 0; if (0>c) c = 0; self.val = array(r, function(i){ return array(c, function(j){ return self.ring.Zero(); }); }); if (is_obj(values)) { for (k in values) { if (!HAS.call(values, k) || (-1 === k.indexOf(','))) continue; v = values[k]; k = k.split(',').map(function(n){return parseInt(trim(n), 10);}); i = k[0]; j = k[1]; if (0<=i && i r) || (0 > c) ? null : new Matrix(ring, array(r, function(i){ return array(c, function(j){ return v; }); })); } ,D: function(ring, r, c, v) { ring = ring || Ring.Z(); var O = ring.Zero(); v = ring.cast(v || O); if (null == c) c = r; // square r = +r; c = +c; return (0 > r) || (0 > c) ? null : new Matrix(ring, array(r, function(i){ return array(c, function(j){ if (i === j) { if (is_array(v) || is_args(v)) return i < v.length ? v[i] : O; else return v; } else { return O; } }); })); } ,T: function(m) { // transpose var rows = m.length, columns = rows ? m[0].length : 0; return array(columns, function(j){ return array(rows, function(i){ return m[i][j]; }); }); } ,ARR: function(ring, a, r, c) { // shape 1-D array into an r x c matrix ring = ring || Ring.Z(); return Matrix(ring, array(r, function(i){ return array(c, function(j){ var k = i*c + j; return k < a.length ? ring.cast(a[k]) : ring.Zero(); }); })); } ,SWAPR: function(m, i, j) { // swap rows i and j if (i !== j) { var t = m[i]; m[i] = m[j]; m[j] = t; } return m; } ,SWAPC: function(m, i, j) { // swap columns i and j if (i !== j) { var k, n = m.length, t; for (k=0; k max[j]) max[j] = s.length; } else { if (s.length > max) max = s.length; } return s; }); } else { var s = String(mi); if (is_array(max)) { if (s.length > max[0]) max[0] = s.length; } else { if (s.length > max) max = s.length; } return s; } }); return m.map(function(mi, i){ return bar + (is_array(mi) ? mi.map(function(mij, j){return pad(mij, is_array(max) ? max[j] : max);}).join(' ') : pad(mi, is_array(max) ? max[0] : max)) + bar; }).join("\n"); } ,toTex: function(m, type) { if (!is_array(m)) return Tex(m); type = 'pmatrix'===type ? 'pmatrix' : 'bmatrix'; return '\\begin{'+type+'}'+m.map(function(x){return is_array(x) ? x.map(function(xi){return Tex(xi);}).join(' & ') : Tex(x);}).join(' \\\\ ')+'\\end{'+type+'}'; } ,toDec: function(m, precision, bar) { if (!is_array(m)) return is_callable(m.toDec) ? m.toDec(precision) : String(m); bar = String(bar || '|'); // compute length of greatest entry in matrix (per column) // so to pad other entries (in same column) same to aling properly var max = is_array(m[0]) ? array(m[0].length, 0) : 0; m = m.map(function(mi, i){ if (is_array(mi)) { return mi.map(function(mij, j){ var d = mij.toDec(precision); if (is_array(max)) { if (d.length > max[j]) max[j] = d.length; } else { if (d.length > max) max = d.length; } return d; }); } else { var d = mi.toDec(precision); if (is_array(max)) { if (d.length > max[0]) max[0] = d.length; } else { if (d.length > max) max = d.length; } return d; } }); return m.map(function(mi, i){ return bar + (is_array(mi) ? mi.map(function(mij, j){return pad(mij, is_array(max) ? max[j] : max);}).join(' ') : pad(mi, is_array(max) ? max[0] : max)) + bar; }).join("\n"); } } ,nr: 0 ,nc: 0 ,val: null ,ring: null ,_str: null ,_tex: null ,_n: null ,_t: null ,_h: null ,_a: null ,_i: null ,_gi: null ,_p: null ,_snf: null ,_lu: null ,_qr: null ,_ldl: null ,_ref: null ,_rref: null ,_rf: null ,_evd: null ,_svd: null ,_rn: null ,_ln: null ,_rs: null ,_cs: null ,_tr: null ,_det: null ,dispose: function() { var self = this; if (self._n && (self === self._n._n)) { self._n._n = null; } if (self._t && (self === self._t._t)) { self._t._t = null; /*self._t._tr = null; self._t._det = null;*/ } if (self._h && (self === self._h._h)) { self._h._h = null; } if (self._i && (self === self._i._i)) { self._i._i = null; } if (self._gi && (self === self._gi._gi)) { self._gi._gi = null; } self.nr = null; self.nc = null; self.val = null; self.ring = null; self._str = null; self._tex = null; self._n = null; self._t = null; self._h = null; self._a = null; self._i = null; self._gi = null; self._p = null; self._snf = null; self._lu = null; self._qr = null; self._ldl = null; self._ref = null; self._rref = null; self._rf = null; self._evd = null; self._svd = null; self._rn = null; self._ln = null; self._rs = null; self._cs = null; self._tr = null; self._det = null; return self; } ,clone: function(raw) { var self = this, m = self.val.map(function(row){return row.slice();}); return true===raw ? m : new Matrix(self.ring, m); } ,map: function(f, raw) { var self = this, m; m = self.val.map(function(vi, i){ return vi.map(function(vij, j){ return f(vij, [i, j], self); }); }); return true===raw ? m : new Matrix(self.ring, m); } ,array: function(column_order) { var self = this; // return matrix as 1-D array of stacking row after row or column after column (if column_order) return column_order ? array(self.nr*self.nc, function(k){ return self.val[k % self.nr][~~(k / self.nr)]; }) : array(self.nr*self.nc, function(k){ return self.val[~~(k / self.nc)][k % self.nc]; }); } ,row: function(r) { var self = this; return 0<=r && r0 chooses diagonal to the right, k<0 diagonal to the left var self = this, r, c; k = k || 0; r = 0 < k ? 0 : -k; c = r ? 0 : k; return 0<=c && c r) r += rows; if (0 > c) c += columns; if (!(0<=r && r A+ = F+ C+ // where F+ = Fh * inv(F * Fh) and C+ = inv(Ch * C) * Ch rf = A.rankf(); C = rf[0]; F = rf[1]; A._gi = F.h().mul(F.mul(F.h()).inv()).mul(C.h().mul(C).inv().mul(C.h())); } } A._gi._gi = ring.isField() ? A : Matrix(field, A); } return A._gi; } ,minor: function(ai, aj, cofactor) { // https://en.wikipedia.org/wiki/Minor_(linear_algebra) var self = this, rows = self.nr, columns = self.nc, ring = self.ring, m; if (rows !== columns) return null; if (1>=rows) return ring.Zero(); ai = +(ai||0); aj = +(aj||0); if (ai<0 || ai>=rows || aj<0 || aj>=columns) return null; m = Matrix(ring, array(rows-1, function(i){ if (i>=ai) i++; return array(columns-1, function(j){ if (j>=aj) j++; return self.val[i][j]; }); })).det(); if ((true === cofactor) && ((ai+aj)&1)) m = m.neg(); return m; } ,adj: function() { // https://en.wikipedia.org/wiki/Adjugate_matrix // https://en.wikipedia.org/wiki/Minor_(linear_algebra)#Inverse_of_a_matrix // https://en.wikipedia.org/wiki/Cramer%27s_rule var self = this, rows, columns, ring; if (null == self._a) { rows = self.nr; columns = self.nc; if (rows !== columns) { self._a = false; } else { ring = self.ring; self._a = Matrix(ring, array(columns, function(j){ return array(rows, function(i){ return self.minor(i, j, true); }); })); } } return self._a; } ,charpoly: function(x) { // https://en.wikipedia.org/wiki/Characteristic_polynomial // https://en.wikipedia.org/wiki/Faddeev%E2%80%93LeVerrier_algorithm // https://en.wikipedia.org/wiki/Samuelson%E2%80%93Berkowitz_algorithm var A = this, rows = A.nr, columns = A.nc, ring, k, n, M, coeff; if (rows !== columns) return null; // only for square matrices if (null == A._p) { x = String(x || 'x'); ring = A.ring; n = rows; coeff = new Array(n+1); M = Matrix(ring, n, n); // zero coeff[n] = ring.One(); for (k=1; k<=n; k++) { M = A.mul(M).map(function(vij, ij){ // .add(I.mul(coeff[n-k+1])) return ij[0]===ij[1] ? vij.add(coeff[n-k+1]) : vij; }); coeff[n-k] = A.mul(M).tr().div(-k); } A._p = ring.PolynomialClass ? Polynomial(coeff.map(function(c){return RationalFunc(c);}), x, ring.CoefficientRing) : Polynomial(coeff, x, ring); } return A._p; } ,add: function(a) { var self = this; if (is_instance(a, Matrix)) { // NOTE: pads with zeroes if dims do not match return Matrix(self.ring, array(stdMath.max(self.nr, a.nr), function(i){ if (i >= a.nr) return self.val[i].slice(); else if (i >= self.nr) return a.val[i].slice(); return array(stdMath.max(self.nc, a.nc), function(j){ if (j >= a.nc) return self.val[i][j]; else if (j >= self.nc) return a.val[i][j]; return self.val[i][j].add(a.val[i][j]); }); })); } if (is_number(a) || is_string(a)) a = self.ring.cast(a); return self.map(function(vij){return vij.add(a);}); } ,sub: function(a) { var self = this; if (is_instance(a, Matrix)) { // NOTE: pads with zeroes if dims do not match return Matrix(self.ring, array(stdMath.max(self.nr, a.nr), function(i){ if (i >= a.nr) return self.val[i].slice(); else if (i >= self.nr) return a.val[i].map(function(aij){return Arithmetic.neg(aij);}); return array(stdMath.max(self.nc, a.nc), function(j){ if (j >= a.nc) return self.val[i][j]; else if (j >= self.nc) return Arithmetic.neg(a.val[i][j]); return self.val[i][j].sub(a.val[i][j]); }); })); } if (is_number(a) || is_string(a)) a = self.ring.cast(a); return self.map(function(vij){return vij.sub(a);}); } ,mul: function(a) { var self = this, n, zero; if (is_instance(a, Matrix)) { //if (self.nc !== a.nr) return null; // dims do not match for multiplication n = stdMath.min(self.nc, a.nr); // generalise multiplication zero = self.ring.Zero(); return Matrix(self.ring, array(self.nr, function(i){ return array(a.nc, function(j){ for (var d=zero,k=0; k= self.nr) return a.val[i].slice(); else if (i >= a.nr) return self.val[i].slice(); return array(stdMath.max(self.nc, a.nc), function(j){ if (j >= self.nc) return a.val[i][j]; else if (j >= a.nc) return self.val[i][j]; return self.val[i][j].mul(a.val[i][j]); }) })); } if (is_number(a) || is_string(a)) a = self.ring.cast(a); return self.map(function(vij){return vij.mul(a);}); } ,prod: function(a) { var self = this, r1, c1, r2, c2, r, c; // kronecker product if (is_instance(a, Matrix)) { r1 = self.nr; c1 = self.nc; r2 = a.nr; c2 = a.nc; r = r1*r2; c = c1*c2; return Matrix(self.ring, array(r, function(i){ var i1 = ~~(i / r2), i2 = i % r2; return array(c, function(j){ var j1 = ~~(j / c2), j2 = j % c2; return self.val[i1][j1].mul(a.val[i2][j2]); }); })); } if (is_number(a) || is_string(a)) a = self.ring.cast(a); return self.map(function(vij){return vij.mul(a);}); } ,div: function(a) { var self = this; if (is_instance(a, Numeric) || Abacus.Arithmetic.isNumber(a) || is_string(a)) { if (is_number(a) || is_string(a)) a = self.ring.cast(a); return self.map(function(vij){return vij.div(a);}); } return self; } ,mod: function(a) { var self = this; if (is_instance(a, Numeric) || Abacus.Arithmetic.isNumber(a) || is_string(a)) { if (is_number(a) || is_string(a)) a = self.ring.cast(a); return self.map(function(vij){return vij.mod(a);}); } return self; } ,divmod: function(a) { var self = this; return [self.div(a), self.mod(a)]; } ,pow: function(n) { var self = this, Arithmetic = Abacus.Arithmetic, pow, b; n = Integer.cast(n); if (n.lt(Arithmetic.O) || n.gt(MAX_DEFAULT)) return null; n = Arithmetic.val(n.num); if (0 === n) { return Matrix.I(self.ring, /*stdMath.min(self.nr,*/ self.nc/*)*/); } else if (1 === n) { return self; } else { // exponentiation by squaring pow = null; b = self; while (0 !== n) { if (n & 1) pow = null == pow ? b : b.mul(pow); n >>= 1; b = b.mul(b); } return pow; } } ,fwdsub: function(b, D) { // self is assumed lower triangular var self = this, ring = self.ring, O = ring.Zero(), i, j, t, L = self.val, n, x, xi, Lii; if (is_instance(b, Matrix)) b = b.col(0); if (is_instance(D, Matrix)) D = D.diag(); b = ring.cast(b); if (D) D = ring.cast(D); n = stdMath.min(self.nr, self.nc, b.length); x = new Array(n); // fraction-free forward substitution for (i=0; i=0; i--) { for (t=O,j=n-1; j>i; j--) t = t.add(U[i][j].mul(x[j])); xi = b[i].sub(t); Uii = U[i][i]; if (Uii.equ(O)) { if (!xi.equ(O)) return null; // no solution } else { if (D) xi = xi.mul(D[i].div(Uii)); else if (Uii.divides(xi)) xi = xi.div(Uii); else return null; // no solution } x[i] = xi; } return x; } ,backsuby: function(y) { // self is assumed upper triangular var self = this, ring = self.ring, O = ring.Zero(), i, j, t, U = self.val, n, x, xi, Uii; if (is_instance(y, Matrix)) y = y.col(0); y = ring.cast(y); n = stdMath.min(self.nr, self.nc, y.length); x = new Array(n); // fraction-free back substitution (alternative version) // y is solution of lower triangular system L*inv(D)*y = P*b // http://ftp.cecm.sfu.ca/personal/pborwein/MITACS/papers/FFMatFacs08.pdf for (i=n-1; i>=0; i--) { for (t=O,j=n-1; j>i; j--) t = t.add(U[i][j].mul(x[j])); xi = U[n-1][n-1].mul(y[i]).sub(t); Uii = U[i][i]; if (!Uii.divides(xi)) return null; // no solution else xi = xi.div(Uii); x[i] = xi; } return x; } ,snf: function() { var self = this, ring, O, I, J, rows, columns, dim, m, left, right, last_j, i, j, upd, ii, jj, non_zero, i1, i0, g, coef1, coef2, coef3, coef4, coef5, tmp, tmp2; // smith normal form // https://en.wikipedia.org/wiki/Smith_normal_form // adapted from Smith Normal Form with sympy (https://gist.github.com/qnighy/ec08799484080343a2da297657ccba65) if (null == self._snf) { ring = self.ring; if (!ring.hasGCD()) { self._snf = false; } else { O = ring.Zero(); I = ring.One(); J = ring.MinusOne(); rows = self.nr; columns = self.nc; dim = stdMath.min(rows, columns); m = self.clone(); left = Matrix.I(ring, rows); right = Matrix.I(ring, columns) last_j = -1; for (i=0; i=0; i0--) { g = ring.xgcd(m.val[i0][i0], m.val[i1][i1]); if (g[0].equ(O)) continue; coef1 = g[1]; coef2 = g[2]; coef3 = m.val[i1][i1].div(g[0]); coef4 = m.val[i0][i0].div(g[0]); tmp = coef2.mul(coef3); tmp2 = I.sub(coef1.mul(coef4)); Matrix.MULR(ring, m.val, i0, i1, I, coef2, coef3, tmp.sub(I)); Matrix.MULC(ring, left.val, i0, i1, I.sub(tmp), coef2, coef3, J); Matrix.MULC(ring, m.val, i0, i1, coef1, tmp2, I, coef4.neg()); Matrix.MULR(ring, right.val, i0, i1, coef4, tmp2, I, coef1.neg()); } } self._snf = [m/*diagonal center matrix*/, left/*left matrix*/, right/*right matrix*/]; } } return self._snf ? self._snf.slice() : self._snf; } ,evd: function() { // eigendecomposition (using the power method) // https://en.wikipedia.org/wiki/Spectral_theorem // https://en.wikipedia.org/wiki/Eigendecomposition_of_a_matrix // https://en.wikipedia.org/wiki/Diagonalizable_matrix // https://en.wikipedia.org/wiki/Power_iteration var self = this, ring = self.ring, m = self.nr, n = self.nc, epsilon, matrixFor1D, e, u, i, j, es, us; return null; /*if (ring.isSymbolic() || (m !== n) || !self.h().equ(self)) return null; // only for square symmetric/hermitian diagonalisable numeric matrices function pow1(A, x, eps, max_iter) { var x0 = null, iter = 0, norm; if (is_class(ring.NumberClass, Complex)) { norm = x.h().mul(x).val[0][0]; if (norm.equ(0)) return null; x = x.div(norm.rad(2)); while (true) { iter++; x0= x; x = A.mul(x); norm = x.h().mul(x).val[0][0]; if (norm.equ(0)) return null; x = x.div(norm.rad(2)); if ((null != max_iter) && (iter >= max_iter)) break; if (x.h().mul(x0).val[0][0].norm().add(eps).gt(1)) break; } } else { norm = x.t().mul(x).val[0][0]; if (norm.equ(0)) return null; x = x.div(norm.rad(2)); while (true) { iter++; x0 = x; x = A.mul(x); norm = x.t().mul(x).val[0][0]; if (norm.equ(0)) return null; x = x.div(norm.rad(2)); if ((null != max_iter) && (iter >= max_iter)) break; if (x.t().mul(x0).val[0][0].abs().add(eps).gt(1)) break; } } return x; } if (null == self._evd) { if (!ring.isField()) { u = Matrix(ring.associatedField(), self); u.evd(); self._evd = u._evd; } else { epsilon = Rational.Epsilon(); es = []; us = []; matrixFor1D = self; for (i=0; i n) { // get svd of transpose and transpose s = self.t().svd(); self._svd = [s[0], s[2].t(), s[1].t()]; } else { evd = self.mul(self.t()).evd(); U = evd[1]; V = self.t().mul(U); s = array(V.nc, function(i){var vm = Matrix(ring, V.col(i)); return vm.t().mul(vm).val[0][0].rad(2);}); V = V.map(function(vij, ij){return vij.div(s[ij[1]]);}); self._svd = [Matrix(ring, s), U.t(), V]; } } return self._svd.slice(); function hypotenuse(a, b) { var r; if (a.abs().gt(b.abs())) { r = b.div(a); return a.abs().mul(r.mul(r).add(ring.One()).rad(2)); } if (!b.equ(ring.Zero())) { r = a.div(b); return b.abs().mul(r.mul(r).add(ring.One()).rad(2)); } return ring.Zero(); } if (null == self._svd) { if (!ring.isField()) { self._svd = Matrix(ring.associatedField(), self).svd(); } else if (m < n) { // get svd of transpose and transpose s = self.t().svd(); self._svd = [s[0], s[2].t(), s[1].t()]; } else { // this version of svd adapted from https://github.com/mljs/matrix Epsilon = Rational.Epsilon(); Limit = Epsilon.inv().integer(); a = self.clone(true); nu = stdMath.min(m, n); ni = stdMath.min(m + 1, n); s = new Array(ni); U = Matrix(ring, m, nu); V = Matrix(ring, n, n); e = new Array(n); work = new Array(m); si = new Array(ni); for (i=0; i=0; k--) { if (!s[k].equ(0)) { for (j=k+1; j=0; k--) { if (k0) { for (k=p-2; k>=-1; k--) { if (k === -1) break; alpha = MIN_VAL.add(eps.mul(s[k].add(s[k + 1].abs()).abs())); if (e[k].abs().lte(alpha) /*|| Number.isNaN(e[k].valueOf())* /) { e[k] = ring.Zero(); break; } } if (k===p-2) { kase = 4; } else { for (ks=p-1; ks>=k; ks--) { if (ks===k) break; t = (ks !== p ? e[ks].abs() : ring.Zero()).add(ks !== k + 1 ? e[ks - 1].abs() : ring.Zero()); if (s[ks].abs().lte(eps.mul(t))) { s[ks] = ring.Zero(); break; } } if (ks===k) { kase = 3; } else if (ks===p-1) { kase = 1; } else { kase = 2; k = ks; } } k++; switch(kase) { case 1: f = e[p - 2]; e[p - 2] = ring.Zero(); for (j=p-2; j>=k; j--) { t = hypotenuse(s[j], f); cs = s[j].div(t); sn = f.div(t); s[j] = t; if (j !== k) { f = sn.neg().mul(e[j - 1]); e[j - 1] = cs.mul(e[j - 1]); } if (wantv) { for (i=0; i= n. Output: Four matrices P, L, D, U, where: P is a nxn permutation matrix, L is a nxn lower triangular matrix, D is a nxn diagonal matrix, U is a nxm upper triangular matrix and P*A = L*inv(D)*U */ defficient = false; //dim = stdMath.min(n, m); U = self.clone(); L = Matrix.I(ring, n); DD = array(n, function(){return O;}); P = Matrix.I(ring, n); oldpivot = I; for (k=0; k=0; p--) if (k0===pivots[p][k]) return p; return -1; }; for (r=0; r pl) pivots.length = pl; self._ref = [m, pivots, det, aug]; } return with_pivots ? self._ref.slice() : self._ref[0]; } ,rref: function(with_pivots, odim) { var self = this, ring, O, I, J, rows, columns, dim, pivots, det, pl, lead, r, i, j, l, a, g, ref, aug; // fraction-free/integer reduced row echelon form (rref), using fraction-free gauss-jordan elimination, or incrementaly from fraction-free row echelon form (gauss elimination) // https://en.wikipedia.org/wiki/Row_echelon_form if (null == self._rref) { ring = self.ring; O = ring.Zero(); I = ring.One(); J = ring.MinusOne(); rows = self.nr; columns = self.nc; dim = columns; // original dimensions, eg when having augmented matrix if (is_array(odim)) dim = stdMath.min(dim, odim[1]); // build rref incrementaly from ref ref = self.ref(true, odim); a = ref[0].concat(ref[3]); pivots = ref[1]; det = ref[2]; pl = pivots.length; for (r=0; r r1) r1 += rows; if (0 > c1) c1 += columns; if (0 > r2) r2 += rows; if (0 > c2) c2 += columns; r1 = stdMath.max(0, stdMath.min(rows-1, r1)); r2 = stdMath.max(0, stdMath.min(rows-1, r2)); c1 = stdMath.max(0, stdMath.min(columns-1, c1)); c2 = stdMath.max(0, stdMath.min(columns-1, c2)); return r1<=r2 && c1<=c2 ? Matrix(ring, array(r2-r1+1, function(i){ return array(c2-c1+1, function(j){ return self.val[r1+i][c1+j]; }); })) : Matrix(ring); } } ,concat: function(a, axis) { var self = this, ring = self.ring, O = ring.Zero(); if (!is_instance(a, Matrix)) return self; axis = axis || 'horizontal'; if ('vertical' === axis) { // | self | // | ---- | // | a | return Matrix(ring, array(self.nr+a.nr, function(i){ return array(stdMath.max(self.nc, a.nc), function(j){ if (j >= self.nc) return i < self.nr ? O : a.val[i-self.nr][j]; else if (j >= a.nc) return i < self.nr ? self.val[i][j] : O; else return i < self.nr ? self.val[i][j] : a.val[i-self.nr][j]; }); })); } else //if ('horizontal' === axis) { // | self | a | return Matrix(ring, array(stdMath.max(self.nr, a.nr), function(i){ return array(self.nc+a.nc, function(j){ if (i >= self.nr) return j < self.nc ? O : a.val[i][j-self.nc]; else if (i >= a.nr) return j < self.nc ? self.val[i][j] : O; else return j < self.nc ? self.val[i][j] : a.val[i][j-self.nc]; }); })); } } ,valueOf: function(r, c) { var self = this, ring = self.ring; r = +(r||0); c = +(c||0); return (0<=r && r= order) order = LEX; } else { order = ORDERINGS & o ? (ORDERINGS & o) : LEX; } // only one main ordering if ((RANDOM & order) && (LEXICAL & order)) order &= ~LEXICAL; if ((MINIMAL & order) && ((COLEX|LEX) & order)) order &= ~(COLEX|LEX); if ((COLEX & order) && (LEX & order)) order &= ~LEX; // random has no reverse if (RANDOM & order) order &= ~REVERSED; return order; } ORDER.LEX = ORDER.LEXICOGRAPHIC = LEX; ORDER.COLEX = ORDER.COLEXICOGRAPHIC = COLEX; ORDER.MINIMAL = ORDER.GRAY = MINIMAL; ORDER.RANDOM = RANDOM; ORDER.REV = ORDER.ANTI = ORDER.REVERSE = ORDER.REVERSED = REVERSED; ORDER.REF = ORDER.REFLECT = ORDER.REFLECTED = REFLECTED; ORDER.REVLEX = ORDER.ANTILEX = ORDER.REVERSELEXICOGRAPHIC = ORDER.ANTILEXICOGRAPHIC = LEX | REVERSED; ORDER.REFLEX = ORDER.REFLECTEDLEXICOGRAPHIC = LEX | REFLECTED; ORDER.REVCOLEX = ORDER.ANTICOLEX = ORDER.REVERSECOLEXICOGRAPHIC = ORDER.ANTICOLEXICOGRAPHIC = COLEX | REVERSED; ORDER.REFCOLEX = ORDER.REFLECTEDCOLEXICOGRAPHIC = COLEX | REFLECTED; Abacus.ORDER = ORDER; // Abacus.Filter, Filter class used to define and combine filters to filter combinatorial object by them Filter = Abacus.Filter = Class({ constructor: function Filter(filter) { var self = this; if (!is_instance(self, Filter)) return new Filter(filter); self.filter = filter || null; } ,__static__: { UNIQUE: function() { return Filter(function(item){ var i, n = item.length, seen = {}; for (i=0; i arguments.length || null == strict) strict = true; if (is_string(dir)) { if ("<" === dir) { dir = 1; strict = true; } else if (">" === dir) { dir = -1; strict = true; } else if ("<=" === dir || "=<" === dir) { dir = 1; strict = false; } else if (">=" === dir || "=>" === dir) { dir = -1; strict = false; } } dir = +dir; dir = -1 === dir ? -1 : 1; return Filter(-1 === dir ? function(item){ for (var item0=item[0],i=1,n=item.length; i=item[i]) || (!strict && item0>item[i])) return false; item0 = item[i]; } return true; }); } ,LEN: function(val, comp) { comp = comp || "=="; val = +val; if (">=" === comp) { return Filter(function(item){ return item.length >= val; }); } else if (">" === comp) { return Filter(function(item){ return item.length > val; }); } else if ("<" === comp) { return Filter(function(item){ return item.length < val; }); } else if ("<=" === comp) { return Filter(function(item){ return item.length <= val; }); } else if ("!=" === comp) { return Filter(function(item){ return item.length !== val; }); } else //if ("==" === comp) { return Filter(function(item){ return item.length === val; }); } } ,VAL: function(pos, val, comp) { comp = comp || "=="; //val = +val; pos = +pos; if (">=" === comp || "=>" === comp) { return Filter(function(item){ return 0<=pos && pos=val; }); } else if (">" === comp) { return Filter(function(item){ return 0<=pos && posval; }); } else if ("<" === comp) { return Filter(function(item){ return 0<=pos && pos=" === comp || "=>" === comp) { return Filter(function(item){ return operate(function(M,i){ if (item[i] > M) M = item[i]; return M; }, -Infinity, null, 0, item.length-1, 1) >= val; }); } else if (">" === comp) { return Filter(function(item){ return operate(function(M,i){ if (item[i] > M) M = item[i]; return M; }, -Infinity, null, 0, item.length-1, 1) > val; }); } else if ("<" === comp) { return Filter(function(item){ return operate(function(M,i){ if (item[i] > M) M = item[i]; return M; }, -Infinity, null, 0, item.length-1, 1) < val; }); } else if ("<=" === comp || "=<" === comp) { return Filter(function(item){ return operate(function(M,i){ if (item[i] > M) M = item[i]; return M; }, -Infinity, null, 0, item.length-1, 1) <= val; }); } else if ("!=" === comp) { return Filter(function(item){ return operate(function(M,i){ if (item[i] > M) M = item[i]; return M; }, -Infinity, null, 0, item.length-1, 1) !== val; }); } else //if ("==" === comp) { return Filter(function(item){ return operate(function(M,i){ if (item[i] > M) M = item[i]; return M; }, -Infinity, null, 0, item.length-1, 1) === val; }); } } ,MIN: function(val, comp) { comp = comp || "=="; val = +val; if (">=" === comp || "=>" === comp) { return Filter(function(item){ return operate(function(M,i){ if (item[i] < M) M = item[i]; return M; }, Infinity, null, 0, item.length-1, 1) >= val; }); } else if (">" === comp) { return Filter(function(item){ return operate(function(M,i){ if (item[i] < M) M = item[i]; return M; }, Infinity, null, 0, item.length-1, 1) > val; }); } else if ("<" === comp) { return Filter(function(item){ return operate(function(M,i){ if (item[i] < M) M = item[i]; return M; }, Infinity, null, 0, item.length-1, 1) < val; }); } else if ("<=" === comp || "=<" === comp) { return Filter(function(item){ return operate(function(M,i){ if (item[i] < M) M = item[i]; return M; }, Infinity, null, 0, item.length-1, 1) <= val; }); } else if ("!=" === comp) { return Filter(function(item){ return operate(function(M,i){ if (item[i] < M) M = item[i]; return M; }, Infinity, null, 0, item.length-1, 1) !== val; }); } else //if ("==" === comp) { return Filter(function(item){ return operate(function(M,i){ if (item[i] < M) M = item[i]; return M; }, Infinity, null, 0, item.length-1, 1) === val; }); } } ,BETWEEN: function(m, M, inclusive) { m = +m; M = +M; if (m > M){ var t=m; m=M; M=t; } if (3 > arguments.length || null == inclusive) inclusive = true; return Filter(inclusive ? function(item){ for (var i=0,n=item.length; iM) return false; } return true; } : function(item){ for (var i=0,n=item.length; i=M) return false; } return true; }); } ,DIFF: function(iter) { return Filter(is_instance(iter, CombinatorialIterator) ? function(item){ return !iter.has(item); } : function(item){ return true; }); } ,MOD: function(iter, item0) { var index0 = null == item0 || !is_instance(iter, CombinatorialIterator) ? Abacus.Arithmetic.O : iter.index(item0); return Filter(is_instance(iter, CombinatorialIterator) ? function(item){ return Abacus.Arithmetic.equ(index0, iter.index(item)); } : function(item){ return true; }); } } ,filter: null ,dispose: function() { var self = this; self.filter = null; return self; } ,apply: function(item, inst) { var filter = this.filter; return filter && is_callable(filter) ? Boolean(filter.call(inst||null, item)) : true; } ,NOT: function() { var self = this; return Filter(function(item){ return !self.apply(item, this); }); } ,OR: function(otherFilter) { var self = this; if (is_callable(otherFilter) || is_instance(otherFilter, Filter)) { if (!is_instance(otherFilter, Filter)) otherFilter = Filter(otherFilter); return Filter(function(item){ return self.apply(item, this) || otherFilter.apply(item, this); }); } return self; } ,XOR: function(otherFilter) { var self = this; if (is_callable(otherFilter) || is_instance(otherFilter, Filter)) { if (!is_instance(otherFilter, Filter)) otherFilter = Filter(otherFilter); return Filter(function(item){ var r1 = self.apply(item, this), r2 = otherFilter.apply(item, this); return (r1 && !r2) || ((!r1) && r2); }); } return self; } ,AND: function(otherFilter) { var self = this; if (is_callable(otherFilter) || is_instance(otherFilter, Filter)) { if (!is_instance(otherFilter, Filter)) otherFilter = Filter(otherFilter); return Filter(function(item){ return self.apply(item, this) && otherFilter.apply(item, this); }); } return self; } }); // Base Iterator Interface & Abstract Class Iterator = Abacus.Iterator = Class({ constructor: function Iterator(name, $) { var self = this, Arithmetic = Abacus.Arithmetic; if (!is_instance(self, Iterator)) return new Iterator(name, $); if ((is_array(name) || is_args(name)) && (is_instance(name[0], Iterator) || is_instance(name[name.length-1], Iterator))) { // sequence of iterators self.name = "Sequence"; self.$ = $ || {}; self.$.seq = slice.call(name); self.$.count = operate(function(count, iter){ return Arithmetic.add(count, iter.total()); }, Arithmetic.O, self.$.seq); self.rewind(); } else if ((is_array(name) || is_args(name))) { // list of items self.name = "List"; self.$ = $ || {}; self.$.seq = slice.call(name); self.$.count = self.$.seq.length; self.rewind(); } else if (is_callable(name)) { // generator function iterator self.name = "Generator"; self.$ = {}; self.$.generator = name; self.$.state = $ || {}; self.$.count = Arithmetic.I; self.rewind(); } else { // iterator subclass self.name = name || "Iterator"; self.$ = $ || {}; self.$.count = self.$.count || Arithmetic.O; } } ,__static__: { Iterable: function Iterable(iter, dir) { var self = this; if (!is_instance(self, Iterable)) return new Iterable(iter, dir); dir = -1 === dir ? -1 : 1; self.next = function() { var next = iter.hasNext(dir) ? iter.next(dir) : null; return null == next ? {done: true} : {value: next}; }; } } ,name: "Iterator" ,$: null ,__index: null ,__item: null ,_index: null ,_item: null ,__subindex: null ,_subindex: null ,__subitem: null ,_subitem: null ,dispose: function() { var self = this; if (self.$.seq && self.$.seq.length) { operate(function(_,iter){if (iter instanceof Iterator) iter.dispose();}, null, self.$.seq); self.$.seq = null; } self.$ = null; self.__index = null; self.__item = null; self._index = null; self._item = null; self.__subindex = null; self._subindex = null; self.__subitem = null; self._subitem = null; return self; } ,filterBy: function(filter) { var self = this, $ = self.$; if (false === filter) { // un-filter if ($.filter) { $.filter = null; //self.rewind(); } } else if (is_instance(filter, Filter) || is_callable(filter)) { $.filter = is_instance(filter, Filter) ? filter : Filter(filter); //self.rewind(); } return self; } ,mapTo: function(output, chained) { var self = this, $ = self.$; if (false === output) { // clear output if ($.output) { $.output = null; } } else if (is_callable(output)) { var prev_output = $.output; if (chained && is_callable(prev_output)) { // chain them $.output = (function(o1, o2) { return function(item, n) { return null == item ? null : o2(o1(item, n), n); }; })(prev_output, output); } else { $.output = output; } } // re-process current item self._item = self.output(self.__item); return self; } ,fuse: function(method, iter, dir) { var self = this, $ = self.$; if ((1 === arguments.length) && (false === method)) { // un-fuse if ($.sub) { $.sub = null; $.submethod = null; $.subcascade = null; $.subcount = null; self.rewind(); } } else if (is_instance(iter, Iterator) && is_callable(method)) { $.sub = iter; $.submethod = method; $.subcascade = -1===dir?-1:1; $.subcount = Abacus.Arithmetic.mul($.count, iter.total()); self.rewind(); } return self; } ,unfuse: function() { return this.fuse(false); } ,juxtaposeWith: function(iter, dir) { return this.fuse(function(item, subitem){ return [].concat(item).concat(subitem); }, iter, dir); } ,state: function(state){ // custom state control for custom generator functions typecasted as iterators var self = this; if (!arguments.length) return self.$.state; self.$.state = state; return self; } // override methods ,output: function(item) { var output = this.$.output; return null == item ? null : (is_callable(output) ? output(item): item); } ,fusion: function(item, subitem) { var self = this, $ = self.$, t; if (!$.sub) return item; if (-1 === $.subcascade){ t = item; item = subitem; subitem = t; } if (null == item || null == subitem) return item || subitem || null; return $.submethod.call(self, item, subitem); } ,order: function() { return this; } ,rewind: function(dir, non_recursive) { var self = this, $ = self.$, i, l, item; dir = -1===dir ? -1 : 1; if (is_array($.seq)) { for (i=0,l=$.seq.length; i dir ? l-1 : 0; do { item = 0<=$.seqindex && $.seqindex$.seqindex || $.seqindex>=$.seq.length) && $.sub && $.sub.hasNext(dir)) { self.rewind(dir, true); item = self.__item; self.__subitem = $.sub.next(dir); } self.__item = item; self._item = self.output(self.__item); self._subitem = $.sub && (null != self._item) && (null != self.__subitem) ? self.fusion(self._item, self.__subitem) : null; } while ($.filter && (null!=next) && !$.filter.apply(next, self)); return next; } else if (is_callable($.generator)) { do { curr = self.__item; next = $.sub ? self._subitem : self._item; // generator should return null as result if finished self.__item = $.generator.call(self, curr, dir, $.state, false/*next item*/); if ((null == self.__item) && $.sub && $.sub.hasNext(dir)) { self.rewind(dir, true); self.__subitem = $.sub.next(dir); } self._item = self.output(self.__item); self._subitem = $.sub && (null != self._item) && (null != self.__subitem) ? self.fusion(self._item, self.__subitem) : null; } while ($.filter && (null!=next) && !$.filter.apply(next, self)); return next; } else { return null; } } ,get: function(up_to) { var self = this, list = [], next, all; // start from current index and ordering and get up to items matching criteria or up to end, // taking into account any filtering applied // incrementing current index as well if (is_callable(up_to)) { while (self.hasNext()) { next = self.next(); if (null == next || !up_to(next)) break; list.push(next); } } else { all = !arguments.length || null==up_to; if (null != up_to) up_to = +up_to; while ((all || list.length maxbase) maxbase = bax; if (bmin < minbase) minbase = bmin; if (dmax > maxdim) maxdim = dmax; if (dmin < mindim) mindim = dmin; }, null, $.seq); $.base = $.maxbase = maxbase; $.minbase = minbase; $.dimension = $.maxdimension = maxdim; $.mindimension = mindim; } else { // base combinatorial class self.n = n || 0; $ = $ || {}; } name = name || "CombinatorialIterator"; $.type = String($.type || "default").toLowerCase(); $.order = $.order || LEX; // default order is lexicographic ("lex") $.rand = $.rand || {}; $.sub = null; $.instance = self; Iterator.call(self, name, $); self.init().order($.order); if (sub && is_instance(sub.iter, CombinatorialIterator)) { sub.method = sub.method || 'project'; if (is_callable(sub.method)) { self.fuse(sub.method, sub.iter, /*sub.pos,*/ sub.cascade); } else if (is_string(sub.method) && -1 !== ['multiply','add','concat','connect','join','combine','complete','interleave','juxtapose','intersperse','project'].indexOf(sub.method)) { var submethod = 'project'===sub.method ? 'projectOn' : (sub.method+'With'); self[submethod](sub.iter, sub.pos, sub.cascade); } } if ($.filter) self.filterBy($.filter); } ,__static__: { // some C-P-T dualities, symmetries & processes at play here :)) C: function(item, N, n, dir){ // C process / symmetry, ie Rotation/Complementation/Conjugation, CC = I var reflected = -1===dir, LEN; if (n+1===item.length) { // fixed-length item, with effective length as extra last pos LEN = is_array(item[n]) ? item[n][0] : item[n]; complementation(item, item, N, reflected ? n-(LEN||1) : 0, reflected ? n-1 : LEN-1); } else { complementation(item, item, N); } return item; } ,D: function(item, N, n, dir) { // C process / symmetry, ie Rotation/Complementation/Conjugation, CC = I // (variation based on complement) var itemlen, reflected = -1===dir, INFO, LEN; if (n+1===item.length) { // fixed-length item, with effective length as extra last pos INFO = item[n]; LEN = is_array(INFO) ? INFO[0] : INFO; item = reflected ? item.slice(n-LEN,n) : item.slice(0,LEN); item = complement(N, item, true); itemlen = item.length; if (itemlendir || (REVERSED&($ && null!=$.order ? $.order : LEX)) ? $.seq[$.seq.length-1].item0(dir) : $.seq[0].item0(dir); } return null; } ,valid: function(item, n, $) { if ((null!=item) && $ && ("sequence"===$.type) && $.seq && $.seq.length) { for (var i=0; i<$.seq.length; i++) { if ($.seq[i][CLASS].valid(item, $.seq[i].n, $.seq[i].$)) return true; } return false; } return false; } ,succ: function(item, index, n, $, dir, item_) { if ((null == n) || (null == item)) return null; var klass = this, Arithmetic = Abacus.Arithmetic, a, b, d, i, seq; dir = -1 === dir ? -1 : 1; if ($ && ("sequence"===$.type)) { seq = $.seq; if (!seq || !seq.length) return null; if (REVERSED & ($ && null!=$.order ? $.order : LEX)) { a = -1; b = seq.length-1; } else { a = 1; b = 0; } i = a*$.seq_curr+b; d = a*dir; while (0<=i && idir?Arithmetic.J:Arithmetic.I), n, $); } ,rand: function(n, $) { var item, klass = this, Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, N, index, seq, i, l, tot; if ($ && ("sequence"===$.type)) { seq = $.seq; if (!seq || !seq.length) return null; // uniform random sampling, taking into account the count of each iterator N = null!=$.last ? $.last : Arithmetic.sub(klass.count(n, $), Arithmetic.I), index = Arithmetic.rnd(O, N); i = 0; l = seq.length; while (Arithmetic.gte(index, tot=seq[i].total())) { index = Arithmetic.sub(index, tot); i++; if (i >=l || Arithmetic.lt(index, O)) break; } return i=sub.$.mindimension && m<=sub.$.maxdimension)) { index = sub[CLASS].rank(item, sub.n, sub.$); if (Arithmetic.gt(index,J)) { found = true; break; } seq_index = Arithmetic.add(seq_index, sub.total()); } } return found ? Arithmetic.add(index, seq_index) : J; } return NotImplemented(); } ,unrank: function(index, n, $) { if ($ && ("sequence"===$.type)) { var klass = this, Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, seq = $.seq, i, l; if (!seq || !seq.length) return null; index = null == index ? null : Arithmetic.num(index); if (null==index || !Arithmetic.inside(index, Arithmetic.J, null!=$.count ? $.count : klass.count(n, $))) return null; l = seq.length; i = 0; while (Arithmetic.gte(index, seq[i].total())) { index = Arithmetic.sub(index, seq[i].total()); i++; if (i >=l || Arithmetic.lt(index, O)) break; } return i max) max = item[i]+1; return item[i]; } return max+subitem[i-item.length]; } : function(i){ // concat return i < item.length ? item[i] : subitem[i-item.length]; })); } else if (("complete" === method) || ("interleave" === method) || ("join" === method) || ("combine" === method)) { // O(n1 + n2) var n1 = item.length, n2 = subitem.length, n3 = n1+n2, i2 = 0, i1 = 0, nk = 0, item_i1 = i1=0; i1--) items.splice(item[i1], 1); i1=0; i2=0; while (i2 < n2) { while ((i1 < n3) && (null != output[i1])) i1++; if (i1 < n3) output[i1] = items[subitem[i2]]; i2++; } return output; } else { return array(n3, "complete" === method ? function(ii){ // complete var v; if (pos_i1 === ii) { v = item_i1; i1++; item_i1 = i1dir ? $.seq.length-1 : 0) : -1; if (RANDOM & order) { // a uniform random traversal over all traversals of the combinatorial space if (("gen" === Abacus.Options.RANDOM) || (1 === $.rand[$.type]) || Arithmetic.gt(tot, Abacus.Options.MAXMEM) || (Arithmetic.isDefault() && 0 > tot/*has overflowed*/)) { // no random unranking supported/enabled // and/or too big to keep in memory // NOTE: given unbiased random generation and large combinatorial sample space (both given) // the probability of having duplicates is close to ZERO (and exactly ZERO on average) // so it indeed produces uniform random traversals (on average) self.__item = klass.rand(n, $); self.__index = O; } else { // random unranking supported // and can keep it in memory => uniform random traversals in all cases // lazy init if (self._traversed) self._traversed.dispose(); self._traversed = null; r = self.random("index", true); try { self.__item = klass.unrank(r, n, $); } catch (e) { r = null; self.__item = klass.rand(n, $); } if (null != r) { self._traversed = new Abacus.BitArray(Arithmetic.val(tot)); self._traversed.set(+r); } else { r = O; } if (null != self.__item) self.__index = r; } self._index = O; // any extra info for fast computation of item succ self._update(); } else { // get a lexicographic or minimal ordering (eg LEX, COLEX, REVLEX, REVCOLEX, GRAY, etc..) self.__item = klass.initial(n, $, dir, true); if (null != self.__item) { self.__index = 0 > dir ? tot_1 : O; // any extra info for fast computation of item succ self._update(); } self._index = self.__index; } self._item = self.output(self.__item); self._prev = (RANDOM & order) || (0 < dir) ? false : null != self.__item; self._next = (0 > dir) && !(RANDOM & order) ? false : null != self.__item; return self; } ,_update: function() { var self = this; // compute and store any extra item information // needed between successive runs to run faster, eg cat or loopless, instead of linear self.item__ = null; return self; } ,order: function(order, dir) { if (!arguments.length) return this.$.order; var self = this, klass = self[CLASS], Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, I = Arithmetic.I, suborder, r, n, $, rewind = true === order, i, l; n = self.n; $ = self.$; if (self._traversed) { self._traversed.dispose(); self._traversed = null; } if (rewind) { order = $.order; } else if (is_string(order)) { if (-1 < (r=order.indexOf('|'))) { suborder = order.substr(r+1); order = ORDER(order.substr(0, r)); } else { suborder = order = ORDER(order); } } else { suborder = order = ORDER(order); } //dir = REVERSED & order ? -1 : 1; // T dir = -1 === dir ? -1 : 1; // T $.order = order; if ("sequence" === $.type && $.seq && $.seq.length) { for (i=0,l=$.seq.length; i dir) && (RANDOM & order)) return null; dI = 0 > dir ? J : I; do { current = $.sub ? self._subitem : self._item; has_curr = null != current; has_subnext = false; if ($.sub && is_instance($.sub, CombinatorialProxy)) { self.__subindex = $.sub.index(); self.__subitem = $.sub.next(dir); has_subnext = null != self.__subitem; has_next = has_subnext; } if (!has_subnext) { if (RANDOM & order) { tot_1 = $.last; if (Arithmetic.lt(self._index, tot_1)) { traversed = self._traversed; if (!traversed) { // random generation self.__item = klass.rand(n, $); self.__index = null; } else { // random unranking // get next un-traversed index, reject if needed r = self.random("index", true); rs = Abacus.Math.rnd() > 0.5 ? J : I; while (traversed.isset(+r)) r = Arithmetic.wrap(Arithmetic.add(r, rs), O, tot_1); traversed.set(+r); self.__item = klass.unrank(r, n, $); if (null != self.__item) self.__index = r; } } else { self._item = self.__item = null; if (self._traversed) { self._traversed.dispose(); self._traversed = null; } } } else { // compute next/prev, using successor methods / loopless algorithms, // WITHOUT using big integer arithmetic self.__item = klass.succ(self.__item, self.__index, n, $, dir, self.item__); if (null != self.__item) self.__index = Arithmetic.add(self.__index, dI); } has_next = null != self.__item; } if (!has_next) { if ($.sub && !is_instance($.sub, CombinatorialProxy) && $.sub.hasNext(dir)) { self.__subindex = $.sub.index(); self.__subitem = $.sub.next(dir); if (null == self.__subitem) { // maybe subIter has filtering applied, so check actual .next() returns non-null self.__subindex = null; self.__subitem = null; if (0 > dir) { self._prev = has_next; self._next = has_curr; } else { self._prev = has_curr; self._next = has_next; } } else { if ("sequence" === $.type && $.seq && $.seq.length) for (i=0,l=$.seq.length; i dir) { self._prev = has_next; self._next = has_curr; } else { self._prev = has_curr; self._next = has_next; } } } else { if (!has_subnext) { self._index = Arithmetic.add(self._index, dI); if (null === self.__index) self.__index = self._index; } if (0 > dir) { self._prev = has_next; self._next = has_curr; } else { self._prev = has_curr; self._next = has_next; } } if (!has_subnext) self._item = self.output(self.__item); if ($.sub) { if (!has_subnext && is_instance($.sub, CombinatorialProxy)) { $.sub.seed(self._item, dir); self.__subindex = $.sub.index(); self.__subitem = $.sub.next(dir); } has_next = has_next && (null != self.__subitem); self._subindex = has_next ? (is_instance($.sub, CombinatorialProxy) ? self._index : Arithmetic.add(Arithmetic.mul(self.__subindex||O,tot), self._index)) : null; self._subitem = has_next ? self.fusion(self._item, self.__subitem) : null; if (0 > dir) self._prev = has_next; else self._next = has_next; } } while ($.filter && (null!=current) && !$.filter.apply(current, self)); // if custom filter, reject if invalid, try next return current; } ,range: function(start, end) { var self = this, Arithmetic = Abacus.Arithmetic, N = Arithmetic.num, O = Arithmetic.O, I = Arithmetic.I, tmp, $ = self.$, tot = $.sub ? $.subcount : $.count, tot_1 = $.sub ? Arithmetic.sub(tot,I) : $.last, range, count, next, i, k, iter_state, dir = 1, argslen = arguments.length, not_randomised = !(RANDOM & $.order); if (argslen < 1) { start = O; end = tot_1; } else if (argslen < 2) { start = N(start); end = tot_1; } else { start = N(start); end = N(end); } start = Arithmetic.wrapR(start, tot); end = Arithmetic.wrapR(end, tot); if (Arithmetic.gt(start, end)) { tmp = start; start = end; end = tmp; dir = -1; } start = Arithmetic.clamp(start, O, tot_1); if (not_randomised) end = Arithmetic.clamp(end, O, tot_1); if (Arithmetic.lte(start, end)) { // store current iterator state iter_state = [ self.$.order ,self.__index ,self._index ,self.__item&&self.__item.slice() ,self._item ,self.__subindex ,self._subindex ,self.__subitem ,self._subitem ,self._prev ,self._next ]; if (not_randomised) self.index(start); count = Arithmetic.val(Arithmetic.sub(end, start)); /*operate(function(range,ri,i){ range[i] = self.next(); return range; }, new Array(count+1), null, 0>dir?count:0, 0>dir?0:count, 0>dir?-1:1);*/ range = new Array(count+1); k = 0; // take into account possible filtering applied while (k<=count) { next = self.next(); if (null == next) break; range[k++] = next; } // truncate if needed if (range.length > k) range.length = k; // reverse if needed if (0 > dir && 1 < range.length) reflection(range, range); // restore previous iterator state self.$.order = iter_state[0]; self.__index = iter_state[1]; self._index = iter_state[2]; self.__item = iter_state[3]; self._item = iter_state[4]; self.__subindex = iter_state[5]; self._subindex = iter_state[6]; self.__subitem = iter_state[7]; self._subitem = iter_state[8]; self._prev = iter_state[9]; self._next = iter_state[10]; self._update(); } else { range = []; } return range; } ,storeState: function(raw) { var self = this, state; state = [ self.$.order ,null == self.__index ? null : self.__index.toString() ,null == self._index ? null : self._index.toString() ,self.__item ,self._item ,null == self.__subindex ? null : self.__subindex.toString() ,null == self._subindex ? null : self._subindex.toString() ,self.__subitem ,self._subitem ,self._prev ,self._next ,self.$.sub ? self.$.sub.storeState(true) : null ]; return raw ? state : JSON.stringify(state); } ,resumeState: function(state) { var self = this, Arithmetic = Abacus.Arithmetic; if (null != state) { state = is_string(state) ? JSON.parse(state) : state; self.$.order = state[0]; self.__index = null == state[1] ? null : Arithmetic.num(state[1]); self._index = null == state[2] ? null : Arithmetic.num(state[2]); self.__item = state[3]; self._item = state[4]; self.__subindex = null == state[5] ? null : Arithmetic.num(state[5]); self._subindex = null == state[6] ? null : Arithmetic.num(state[6]); self.__subitem = state[7]; self._subitem = state[8]; self._prev = state[9]; self._next = state[10]; if (self.$.sub && state[11]) self.$.sub.resumeState(state[11]); } return self; } }); // a proxy for dynamically instantiating other combinatorial iterators CombinatorialProxy = Abacus.CombinatorialProxy = Class(CombinatorialIterator, { constructor: function CombinatorialProxy(combIterFactory, $) { var self = this, iter; if (!is_instance(self, CombinatorialProxy)) return new CombinatorialProxy(combIterFactory, $); $ = $ || {}; $.factory = is_callable(combIterFactory) ? combIterFactory : null; $.iter = null; if ($.factory && (true===$.factory.SINGLETON)) { iter = $.factory(); if (is_instance(iter, CombinatorialIterator)) { $.iter = iter; $.count = iter.total(); $.base = iter.base(); $.dimension = iter.dimension(); } } else { $.base = 0; $.dimension = 1; } CombinatorialIterator.call(self, "Proxy", 0, $); } ,__static__: { count: function(n, $) { return $ && $.iter ? $.iter.total() : Abacus.Arithmetic.I; } ,initial: NotImplemented ,valid: NotImplemented ,succ: NotImplemented ,rank: NotImplemented ,unrank: NotImplemented ,singleton: function(factory) { var iter = null; var f = function(item) { if (!iter) iter = factory(item); return iter; }; f.SINGLETON = true; return f; } } ,dispose: function() { var self = this; self.$.factory = null; if (self.$.iter && is_instance(self.$.iter, CombinatorialIterator)) self.$.iter.dispose(); self.$.iter = null; return CombinatorialIterator[PROTO].dispose.call(self); } ,seed: function(item, dir) { var self = this, $ = self.$, prev = $.iter; $.iter = $.factory && (null!=item) ? $.factory(item) : null; if (prev && (prev !== $.iter)) { prev.dispose(); prev = null; } if (!is_instance($.iter, CombinatorialIterator)) $.iter = null; if ($.iter && (prev !== $.iter) && (-1 === dir)) $.iter.rewind(dir); return self; } ,order: function(order, dir) { var self = this, $ = self.$; if ($.iter) $.iter.order(order, dir); return self; } ,hasNext: function(dir) { var $ = this.$; return $.iter ? $.iter.hasNext(dir) : false; } ,next: function(dir) { var $ = this.$; return $.iter ? $.iter.next(dir) : null; } ,index: function() { var $ = this.$; return $.iter ? $.iter.index.apply($.iter, arguments) : null; } ,item: function() { var $ = this.$; return $.iter ? $.iter.item.apply($.iter, arguments) : null; } ,random: function() { var $ = this.$; return $.iter ? $.iter.random() : null; } }); // a iterator for arithmetic progressions from MIN up to MAX, by step=STEP Progression = Abacus.Progression = Class(Iterator, { constructor: function Progression(min, step, max, $) { var self = this, Arithmetic = Abacus.Arithmetic, N = Arithmetic.num, O = Arithmetic.O, I = Arithmetic.I; if (!is_instance(self, Progression)) return new Progression(min, step, max, $); if (is_array(min) || is_args(min)) { $ = step || {}; step = 1 dir) { if (Arithmetic.INF === self._max) { self.__item = null; self._item = null; } else { if ('geometric' === self.$.type) self.__item = Arithmetic.mul(self._min, Arithmetic.pow(self._step, self.$.last)); else self.__item = Arithmetic.add(self._min, Arithmetic.mul(self._step, self.$.last)); self._item = self.output($.NumberClass ? new $.NumberClass(self.__item) : self.__item); } } else { self.__item = self._min; self._item = self.output($.NumberClass ? new $.NumberClass(self.__item) : self.__item); } if ($.sub && (true !== non_recursive)) { $.sub.rewind(dir); self.__subitem = $.sub.next(dir); self._subitem = (null != self._item) && (null != self.__subitem) ? self.fusion(self._item, self.__subitem) : null; } return self; } ,hasNext: function(dir) { dir = -1===dir ? -1 : 1; var self = this, $ = self.$, Arithmetic = Abacus.Arithmetic; return Arithmetic.INF === self._max ? ((0 < dir) && ($.sub ? (null != self.__subitem) : true)) : ($.sub ? (null != self._subitem) : (null != self.__item)); } ,next: function(dir) { dir = -1===dir ? -1 : 1; var self = this, $ = self.$, Arithmetic = Abacus.Arithmetic, current, prev; do { prev = self.__item; current = $.sub ? self._subitem : self._item; if (null != prev) { if ("geometric" === $.type) { // geometric progression if (0 > dir) { if (Arithmetic.equ(prev, self._min)) self.__item = null; else self.__item = Arithmetic.div(prev, self._step); } else { if ((Arithmetic.INF !== self._max) && Arithmetic.equ(prev, self._max)) self.__item = null; else self.__item = Arithmetic.mul(prev, self._step); } } else { // arithmetic progression if (0 > dir) { if (Arithmetic.equ(prev, self._min)) self.__item = null; else self.__item = Arithmetic.sub(prev, self._step); } else { if ((Arithmetic.INF !== self._max) && Arithmetic.equ(prev, self._max)) self.__item = null; else self.__item = Arithmetic.add(prev, self._step); } } if ((null!=self.__item) && (Arithmetic.lt(self.__item, self._min) || ((Arithmetic.INF !== self._max) && Arithmetic.gt(self.__item, self._max)))) { self.__item = null; } self._item = null==self.__item ? null : self.output($.NumberClass ? new $.NumberClass(self.__item) : self.__item); } if ((null == self.__item) && $.sub && $.sub.hasNext(dir)) { self.rewind(dir, true); self.__subitem = $.sub.next(dir); self._subitem = null != self._item && null != self.__subitem ? self.fusion(self._item, self.__subitem) : null; } } while ($.filter && (null!=current) && !$.filter.apply(current, self)); return current; } ,storeState: function(raw) { var self = this, state; state = [ self._min.toString() ,self._step.toString() ,self._max.toString() ,null == self.__item ? null : self.__item.toString() ,null == self._item ? null : self._item.toString() ,null == self.__subitem ? null : self.__subitem.toString() ,null == self._subitem ? null : self._subitem.toString() ,self.$.sub ? self.$.sub.storeState(true) : null ]; return raw ? state : JSON.stringify(state); } ,resumeState: function(state) { var self = this, Arithmetic = Abacus.Arithmetic; if (null != state) { state = is_string(state) ? JSON.parse(state) : state; self._min = "-Infinity" === state[0] ? Arithmetic.NINF : ("Infinity" === state[0] ? Arithmetic.INF : Arithmetic.num(state[0])); self._step = "-Infinity" === state[1] ? Arithmetic.NINF : ("Infinity" === state[1] ? Arithmetic.INF : Arithmetic.num(state[1])); self._max = "-Infinity" === state[2] ? Arithmetic.NINF : ("Infinity" === state[2] ? Arithmetic.INF : Arithmetic.num(state[2])); self.__item = null == state[3] ? null : Arithmetic.num(state[3]); self._item = null == state[4] ? null : Arithmetic.num(state[4]) self.__subitem = null == state[5] ? null : Arithmetic.num(state[5]) self._subitem = null == state[6] ? null : Arithmetic.num(state[6]) if (self.$.sub && state[7]) self.$.sub.resumeState(state[7]); } return self; } }); HashSieve = function HashSieve() { var self = this, _hash = null; if (!is_instance(self, HashSieve)) return new HashSieve(); _hash = Obj(); //{}; self.dispose = function() { self.empty(); _hash = null; return self; }; self.empty = function() { var i, iter, j, l; if (!_hash) return self; for (i in _hash) { if (!HAS.call(_hash, i) || null == _hash[i]) continue; for (iter=_hash[i],j=0,l=iter.length; j dir) return null; var self = this, $ = self.$, pp, p2, pl, ps, multiples = self._multiples, small_primes = self._small_primes, Arithmetic = Abacus.Arithmetic, two = Arithmetic.II, prime = self.__item, output; do { // Eratosthenes sieve with pre-computed small primes list // O(n log(log(n))) for getting all primes up to n if (self._p < small_primes.length) { // get primes from the pre-computed list //self.__index = Arithmetic.num(self._p); prime = small_primes[self._p++]; // add odd multiples of this prime to the list for crossing out later on, // start from p^2 since lesser multiples are already crossed out by previous primes if (Arithmetic.gt(prime, two)) { pp = Arithmetic.mul(prime, prime); p2 = Arithmetic.add(prime, prime); pl = small_primes[small_primes.length-1]; // last prime in list if (Arithmetic.lt(pp, pl)) { // take multiples of this prime AFTER the last prime in list // lesser multiples have already been taken care of ps = Arithmetic.div(Arithmetic.sub(pl, pp), p2); pp = Arithmetic.add(pp, Arithmetic.mul(ps, p2)); if (Arithmetic.lte(pp, pl)) pp = Arithmetic.add(pp, p2); } multiples.add(new Progression(pp, p2, Arithmetic.INF)); } } else { if (Arithmetic.equ(prime, two)) { // first odd prime prime = Arithmetic.num(3); } else { // check candidate primes, using odd increments, ie avoid multiples of two faster do { prime = Arithmetic.add(prime, two); } while (multiples.has(prime)); } // add odd multiples of this prime to the list for crossing out later on, // start from p^2 since lesser multiples are already crossed out by previous primes pp = Arithmetic.mul(prime, prime); p2 = Arithmetic.add(prime, prime); multiples.add(new Progression(pp, p2, Arithmetic.INF)); //self.__index = Arithmetic.add(self.__index, Arithmetic.I); } output = self.output($.NumBerClass ? new $.NumBerClass(prime) : prime); } while ($.filter && (null!=output) && !$.filter.apply(output, self)); self.__item = prime; self._item = output; return prime; } }); // https://en.wikipedia.org/wiki/Outer_product // https://en.wikipedia.org/wiki/Kronecker_product // https://en.wikipedia.org/wiki/Tensor_product // also a combinatorial iterator for partial (explicit and/or as conditional expressions) combinatorial data Tensor = Abacus.Tensor = Class(CombinatorialIterator, { // extends and implements CombinatorialIterator constructor: function Tensor(/*dims here ..*/) { var self = this, sub = null, n = slice.call(arguments), $; $ = n.length && !is_instance(n[n.length-1], CombinatorialIterator) && !is_array(n[n.length-1]) && (n[n.length-1] !== +n[n.length-1]) ? n.pop() || {} : {}; if (n.length && is_array(n[0])) n = n[0]; if (!n || !n.length) n = []; if (!is_instance(self, Tensor)) return new Tensor(n, $); $.type = String($.type || "tensor").toLowerCase(); $.order = $.order || LEX; $.rand = $.rand || {}; if ("partial" === $.type) { n = is_array(n)&&n.length ? n[0] : n; var nsub = -1, data = $.data||[], pos = $.position||null; if (is_instance(n, CombinatorialIterator)) { sub = n; n = sub.base(); // partial n, needs plus the position data of this instance nsub = n; } else { sub = $.sub; } n = (+(n||0))||0; if (is_obj(data)) { //eg. {0:"{0..4}",1:"[0]+1",..} pos = []; data = KEYS(data).map(function(p){ p = +p; pos.push(p); return data[p]; }); } if (is_args(data)) data = slice.call(data); if (is_args(pos)) pos = slice.call(pos); if (data.length && (is_string(data[0]) || (data[0].length && (true === data[0][0] || false === data[0][0])))) { // conditions: ALGEBRAIC(STRING EXPR) AND/OR BOOLEAN(POSITIVE / NEGATIVE) => [values] per position if (nsub === n) { n += data.length; nsub = -1; } data = Tensor.generate(n, data, pos, $.ordering||null); } if (nsub === n) { n += (data.length?data[0].length:0)||0; nsub = -1; } $.data = data; $.position = pos || array((data.length?data[0].length:0)||0, 0, 1); $.dimension = $.position.length; $.base = n; $.rand["partial"] = 1; } else { if ("tuple" === $.type) { n[0] = n[0]||1; n[1] = n[1]||1; if (is_instance(n[0], CombinatorialIterator)) { sub = n[0]; n[0] = sub.dimension(); } else if (is_instance(n[1], CombinatorialIterator)) { sub = n[1]; n[1] = sub.base(); } else { sub = $.sub; } $.base = n[1]; $.dimension = stdMath.max(0, n[0]); if ("gray" === $.output) $.output = function(item, n){ return Tensor.toGray(item,n[1]); }; } else { var m_M = operate(function(m_M, k){ if (k < m_M[0]) m_M[0] = k; if (k > m_M[1]) m_M[1] = k; return m_M; }, [Infinity,0], n); $.base = n; $.minbase = m_M[0]; $.maxbase = m_M[1]; $.dimension = n.length; if ("gray" === $.output) { $.output = function(item, n){ return Tensor.toGray(item,n); }; } else if ("inversion" === $.output) { $.output = function(item, n){ return Tensor.inversion(item); }; } else if (is_array($.output)) { var BASE = $.output; $.output = function(item, n){ return Tensor.component(item,BASE); }; } } } CombinatorialIterator.call(self, "Tensor", n, $, sub?{method:"partial"===$.type?($.submethod||"complete"):$.submethod,iter:sub,pos:"partial"===$.type?($.subpos||$.position):$.subpos,cascade:$.subcascade}:null); } ,__static__: { C: CombinatorialIterator.C ,P: CombinatorialIterator.P ,T: CombinatorialIterator.T ,DUAL: CombinatorialIterator.DUAL ,count: function(n, $) { var O = Abacus.Arithmetic.O, type = $ && $.type ? $.type : "tensor"; return "partial"===type ? ($.data&&$.data.length ? Abacus.Arithmetic.num($.data.length) : O) : ("tuple"===type ? (!n || (0 >= n[0]) ? O : exp(n[1], n[0])) : (!n || !n.length ? O : product(n))); } ,initial: function(n, $, dir) { // some C-P-T dualities, symmetries & processes at play here // last (0>dir) is C-symmetric of first (0 dir ? $.data[$.data.length-1] : $.data[0]) : null; } else { // O(n) item = "tuple" === type ? ( !n[0] ? [] : (0 > dir ? array(n[0], n[1]-1, 0) : array(n[0], 0, 0)) ) : ( !n.length ? [] : (0 > dir ? array(n.length, function(i){return n[i]-1;}): array(n.length, 0, 0)) ); item = klass.DUAL(item, n, $); } return item; } ,valid: function(item, n, $) { var klass = this, type = $ && $.type ? $.type : "tensor", nd, i; if (!item) return false; if ("partial" === type) { return 0 <= find($.data, item, true); } else { item = klass.DUAL(item.slice(), n, $); if ("tuple" === type) { nd = n[0]; if (!nd || nd !== item.length) return false; for (n=n[1],i=0; i item[i] || item[i] >= n) return false; } } else { nd = n.length; if (!nd || nd !== item.length) return false; for (i=0; i item[i] || item[i] >= n[i]) return false; } } } return true; } ,succ: function(item, index, n, $, dir, TI) { if (!n || (null == item)) return null; var type = $ && $.type ? $.type : "tensor", order = $ && null!=$.order ? $.order : LEX, Arithmetic = Abacus.Arithmetic, ind; dir = -1 === dir ? -1 : 1; if ("partial" === type) { if (!$.data || !$.data.length) return null; if (REVERSED & order) { dir = -dir; if (null != index) index = Arithmetic.sub(Arithmetic.num($.data.length-1),index); } if (null == index) index = find($.data, item, true); ind = Arithmetic.val(index); return 0>dir ? (0<=ind-1 ? $.data[ind-1] : null) : (0<=ind && ind+1<$.data.length ? $.data[ind+1] : null); } return !n[0] || (0 >= n[0]) ? null : next_tensor(item, n, dir, type, order, TI); } ,rand: function(n, $) { var rndInt = Abacus.Math.rndInt, klass = this, item, type = $ && $.type ? $.type : "tensor"; if ("partial" === type) { item = $.data&&$.data.length ? $.data[rndInt(0,$.data.length-1)] : null; } else { item = "tuple" === type ? ( // p ~ 1 / n^k, O(n) !n[0] ? [] : array(n[0], function(i){return rndInt(0, n[1]-1);}) ) : ( // p ~ 1 / n1*n2*..nk, O(n) !n.length ? [] : array(n.length, function(i){return rndInt(0, n[i]-1);}) ); item = klass.DUAL(item, n, $); } return item; } // random unranking, another method for unbiased random sampling ,randu: CombinatorialIterator.rand ,rank: function(item, n, $) { var klass = this, Arithmetic = Abacus.Arithmetic, order = $ && null!=$.order?$.order:LEX, type = $ && $.type ? $.type : "tensor", add = Arithmetic.add, sub = Arithmetic.sub, mul = Arithmetic.mul, index = Arithmetic.O, J = Arithmetic.J, nd, i; if (!item) return J; if ("partial" === type) { index = Arithmetic.num(find($.data, item, true)); } else { // O(n) item = klass.DUAL(item, n, $); if ("tuple" === type) { nd = n[0]; if (!nd || nd !== item.length) return J; for (n=n[1],i=0; i item[i] || item[i] >= n) return J; index = add(mul(index, n), item[i]); } } else { nd = n.length; if (!nd || nd !== item.length) return J; for (i=0; i item[i] || item[i] >= n[i]) return J; index = add(mul(index, n[i]), item[i]); } } } if ((!(COLEX&order) && (REVERSED&order)) || ((COLEX&order) && !(REVERSED&order))) index = sub($ && null!=$.last?$.last:sub(klass.count(n, $),Arithmetic.I), index); return index; } ,unrank: function(index, n, $) { var klass = this, Arithmetic = Abacus.Arithmetic, order = $ && null!=$.order?$.order:LEX, type = $ && $.type ? $.type : "tensor", sub = Arithmetic.sub, mod = Arithmetic.mod, div = Arithmetic.div, val = Arithmetic.val, r, b, i, t, item, nd; index = null == index ? null : Arithmetic.num(index); if (null==index || !Arithmetic.inside(index, Arithmetic.J, $ && null!=$.count ? $.count : klass.count(n, $))) return null; if ((!(COLEX&order) && (REVERSED&order)) || ((COLEX&order) && !(REVERSED&order))) index = sub($ && null!=$.last?$.last:sub(klass.count(n, $),Arithmetic.I), index); if ("partial" === type) { if (!$.data || !$.data.length) return null; index = val(index); item = 0<=index && index<$.data.length ? $.data[index] : null; } else { // O(n) if ("tuple" === type) { nd = n[0]; if (!nd) return []; item = new Array(nd); b = n[1]; for (r=index,i=nd-1; i>=0; i--) { t = mod(r, b); r = div(r, b); item[i] = val(t); } } else { nd = n.length; if (!nd) return []; item = new Array(nd); for (r=index,i=nd-1; i>=0; i--) { b = n[i]; t = mod(r, b); r = div(r, b); item[i] = val(t); } } item = klass.DUAL(item, n, $); } return item; } ,toGray: function(item, n) { return gray(new Array(item.length), item, n); } ,fromGray: function(item, n) { return igray(new Array(item.length), item, n); } ,inversion: function(inv) { // assume inv is tensor component of dimensions: (1,2,..,n-1,n) in this order var i, n = inv.length, perm = n ? [0] : []; for (i=1; i= affine.length || null == affine[i]) return item[i]; var T = affine[i]; return is_number(T) ? item[i]+T : T[0]*item[i]+(T[1]||0); }); } : ID; } ,conditional: conditional_combinatorial_tensor ,generate: gen_combinatorial_data } }); function next_tensor(item, N, dir, type, order, TI) { //maybe "use asm" var n = N, k, i, j, i0, i1, DI, a, b, MIN, MAX; if ("tuple" === type) { k=n[0]; n=n[1]; } else { k=n.length; } // some C-P-T dualities, symmetries & processes at play here // LEX MIN = 0; MAX = k-1; DI = 1; i0 = MAX; i1 = MIN; a = 1; b = 0; if (COLEX & order) { //CP-symmetric of LEX DI = -DI; i0 = MAX-i0; i1 = MAX-i1; a = -a; b = MAX-b; } if (REFLECTED & order) { //P-symmetric of LEX DI = -DI; i0 = MAX-i0; i1 = MAX-i1; a = -a; b = MAX-b; } if (REVERSED & order) { //T-symmetric of LEX dir = -dir; } // constant average delay (CAT) if (0 > dir) { if ("tuple" === type) { i = i0; while (MIN<=i && MAX>=i && item[i]===0) i-=DI; if (MIN<=i && MAX>=i) for (n=n-1,item[i]=item[i]-1,j=i+DI; MIN<=j && MAX>=j; j+=DI) item[j] = n; //else last item else item = null; } else { i = i0; while (MIN<=i && MAX>=i && item[i]===0) i-=DI; if (MIN<=i && MAX>=i) for (item[i]=item[i]-1,j=i+DI; MIN<=j && MAX>=j; j+=DI) item[j] = n[a*j+b]-1; //else last item else item = null; } } else { if ("tuple" === type) { i = i0; while (MIN<=i && MAX>=i && item[i]+1===n) i-=DI; if (MIN<=i && MAX>=i) for (item[i]=item[i]+1,j=i+DI; MIN<=j && MAX>=j; j+=DI) item[j] = 0; //else last item else item = null; } else { i = i0; while (MIN<=i && MAX>=i && item[i]+1===n[a*i+b]) i-=DI; if (MIN<=i && MAX>=i) for (item[i]=item[i]+1,j=i+DI; MIN<=j && MAX>=j; j+=DI) item[j] = 0; //else last item else item = null; } } return item; } // https://en.wikipedia.org/wiki/Permutations Permutation = Abacus.Permutation = Class(CombinatorialIterator, { // extends and implements CombinatorialIterator constructor: function Permutation(n, $) { var self = this, sub = null; if (!is_instance(self, Permutation)) return new Permutation(n, $); $ = $ || {}; $.type = String($.type || "permutation").toLowerCase(); n = n||0; if (is_instance(n, CombinatorialIterator)) { sub = n; n = sub.dimension(); } else { sub = $.sub; } $.base = n; $.dimension = stdMath.max(0, n); // random ordering for derangements / involutions / connecteds // is based on random generation, instead of random unranking $.rand = $.rand || {}; if ("multiset" === $.type) { $.multiplicity = is_array($.multiplicity) && $.multiplicity.length ? $.multiplicity.slice() : array($.dimension, 1, 0); $.multiplicity = $.multiplicity.concat(array($.dimension-operate(addn, 0, $.multiplicity), 1, 0)); $.base = $.multiplicity.length; $.multiset = multiset($.multiplicity, $.dimension); } CombinatorialIterator.call(self, "Permutation", n, $, sub?{method:$.submethod,iter:sub,pos:$.subpos,cascade:$.subcascade}:null); } ,__static__: { C: CombinatorialIterator.C ,P: CombinatorialIterator.P ,T: CombinatorialIterator.T ,DUAL: CombinatorialIterator.DUAL ,count: function(n, $) { var Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, //factorial = Abacus.Math.factorial, stirling = Abacus.Math.stirling, type = $ && $.type ? $.type : "permutation", kcycles = $ && null!=$['cycles='] ? $['cycles=']|0 : null, kfixed = $ && null!=$['fixed='] ? $['fixed=']|0 : null ; if (0 > n) return O; else if ("cyclic" === type) return Arithmetic.num(n); else if ("multiset" === type) return factorial(n, $.multiplicity); else if ("derangement" === type) return null!=kfixed ? Arithmetic.mul(factorial(n,kfixed),factorial(n-kfixed,false)) : factorial(n,false); else if ("involution" === type) return factorial(n, true); else if ("connected" === type) return factorial(n-1); else//if ("permutation" === type) return null!=kcycles ? stirling(n,kcycles,1) : factorial(n); } ,initial: function(n, $, dir) { // some C-P-T dualities, symmetries & processes at play here // last (0>dir) is C-symmetric of first (0=0; k--) item.splice(i[k], 1); k = mergesort(item.slice(), 1, true); j = item.map(function(c){return k.indexOf(c);}); //i = Combination.DUAL(i, [n, fixed], {base:n, dimension:fixed, order:order}); //j = Permutation.DUAL(j, n-fixed, {order:order}); return [i, j]; } function decompose_kcycles(item, n, cycles, order) { var i, j, k, l, m, w, z, s, p; item = permutation2cycles(item); i = new Array(n+1); i[n] = [n, new Array(n), array(item.length, 0, 0)]; j = []; for (k=0; k k || k > n || k+1===n) return null; var next0, next1 = Permutation.succ(item[1], null, n-k, {type:"derangement", order:order}, dir); if (null == next1) { next0 = Combination.succ(item[0], null, [n, k], {type:"combination", order:order}, dir); if (null == next0) return null; return [next0, Permutation.initial(n-k, {type:"derangement", order:order}, dir)]; } else { return [item[0], next1]; } } function next_kcycles(item, n, k, dir, order) { if (0 > k || k > n) return null; var i, j, next0, next1, order2 = REVERSED&order ? LEX | REVERSED : LEX; for (i=item[1].length-1; i>=0; i--) { next1 = Permutation.succ(item[1][i], null, item[1][i].length, {type:"permutation", order:order}, dir); if (null == next1) { item[1][i] = Permutation.initial(item[1][i].length, {type:"permutation", order:order}, dir); } else { item[1][i] = next1; break; } } if (null == next1) { next0 = SetPartition.succ(item[0], null, n, {"parts=":k, order:LEX | (order&REVERSED ? REVERSED : 0)}, dir); if (null == next0) return null; return [next0, operate(function(partition, i){ partition[item[0][i]].push(i); return partition; }, array(k, function(){return [];}), null, 0, n-1, 1).filter(function(p){return 1 < p.length;}).map(function(p){return Permutation.initial(p.length-1, {type:"permutation", order:order}, dir);})]; } else { return [item[0], item[1]]; } } function next_permutation(item, N, dir, type, order, multiplicity, PI) { //maybe "use asm" var n = N, m = null == multiplicity ? n : multiplicity, k, kl, l, r, s, s0, fixed, done, k0, DK, a, b, da, db, MIN, MAX; if (0 >= n) return null; if ("connected" === type) { return next_permutation(item, N-1, dir, "permutation", order, null, PI); } // some C-P-T dualities, symmetries & processes at play here // LEX MIN = 0; MAX = n-1; DK = 1; k0 = MAX; a = 1; b = 0; da = 1; db = 0; if (COLEX & order) { //CP-symmetric of LEX DK = -DK; k0 = MAX-k0; a = -a; b = m-1-b; dir = -dir; } if (REFLECTED & order) { //P-symmetric of LEX DK = -DK; k0 = MAX-k0; da = -1; db = m-1; } if (REVERSED & order) { //T-symmetric of LEX dir = -dir; } // constant average delay (CAT) for permutations & multisets // linear worst-case for derangements // linear for cyclic shift permutations if (0 > dir) { if ("cyclic" === type) { k = MAX-k0; if (a*item[k]+b > 0) { //item = [item[n-1]].concat(item.slice(0,-1)); da = n-1; DK = n+DK; for (l=0; l a[k + 1]. // taking into account equal elements, generates multiset permutations k = k0-DK; while (MIN<=k && k<=MAX && a*item[k]<=a*item[k+DK]) k-=DK; // If no such index exists, the permutation is the last permutation. if (MIN<=k && k<=MAX) { //Find the largest index kl greater than k such that a[k] > a[kl]. kl = k0; while (MIN<=kl && kl<=MAX && DK*(kl-k)>0 && a*item[k]<=a*item[kl]) kl-=DK; //Swap the value of a[k] with that of a[l]. s = item[k]; item[k] = item[kl]; item[kl] = s; //Reverse the sequence from a[k + 1] up to and including the final element a[n]. l = k+DK; r = k0; while (MIN<=l && l<=MAX && MIN<=r && r<=MAX && DK*(r-l)>0) { s = item[l]; item[l] = item[r]; item[r] = s; fixed = fixed || (da*l+db === item[l]) || (da*r+db === item[r]); l+=DK; r-=DK; } if ("derangement" === type) { if (MIN<=kl && kl<=MAX) fixed = fixed || (da*kl+db === item[kl]); if (MIN<=r && r<=MAX) fixed = fixed || (da*r+db === item[r]); // TODO: find a way check for fixed without looping over the range here for (fixed=fixed||(da*k+db === item[k]),l=k-DK; !fixed && MIN<=l && l<=MAX; l-=DK) fixed = da*l+db === item[l]; } else { fixed = false; } } //else last item else item = null; // every 2-3 permutations is derangement on average, ie p(D) = 1/e } while (item && fixed); } } else { if ("cyclic" === type) { k = MAX-k0; if (a*item[k]+b < n-1) { //item = item.slice(1).concat([item[0]]); da = n+1; DK = n+DK; for (l=0; l0) { r = l+1; // add new cycle k0 = PI[l]+1; while (k0<=MAX && k0!==item[k0]) k0++; if (k0<=MAX) { k = k0+1; while (k<=MAX && k!==item[k]) k++; if (k<=MAX && (s===s0 || k0!==PI[l+2] || k!==PI[l+3])) { // new swap l+=2; r=l+1; PI[l] = k0; PI[r] = k; item[PI[l]] = PI[r]; item[PI[r]] = PI[l]; s++; fixed = false; break; } } // restore cycle item[PI[l]] = PI[l]; item[PI[r]] = PI[r]; s--; k = PI[r]+1; while (k<=MAX && k!==item[k]) k++; if (k<=MAX) { // extend cycle to right PI[r] = k; item[PI[l]] = PI[r]; item[PI[r]] = PI[l]; s++; fixed = false; break; } k0 = PI[l]-1; while (MIN<=k0 && k0!==item[k0]) k0--; if (MIN<=k0) { k = k0+1; while (k<=MAX && k!==item[k]) k++; if (k<=MAX) { // extend cycle to left PI[l] = k0; PI[r] = k; item[PI[l]] = PI[r]; item[PI[r]] = PI[l]; s++; fixed = false; break; } } // next cycle l-=2; } } PI[0] = 0 > s ? 0 : s; if (fixed) item = null; */ // adapted from http://www.jjj.de/fxt/#fxt (Jörg Arndt) k = n; fixed = true; while (fixed && k--) { kl = item[k]; // inverse perm == perm item[k] = k; item[kl] = kl; // undo prior swap while (kl--) { if (item[kl] === kl) { item[k] = kl; item[kl] = k; // swap fixed = false; break; } } } if (fixed) item = null; // last } else//if (("multiset" === type) || ("derangement" === type) || ("permutation" === type)) { // variation of http://en.wikipedia.org/wiki/Permutation#Systematic_generation_of_all_permutations do { fixed = false; //Find the largest index k such that a[k] < a[k + 1]. // taking into account equal elements, generates multiset permutations k = k0-DK; while (MIN<=k && k<=MAX && a*item[k]>=a*item[k+DK]) k-=DK; // If no such index exists, the permutation is the last permutation. if (MIN<=k && k<=MAX) { //Find the largest index kl greater than k such that a[k] < a[kl]. kl = k0; while (MIN<=kl && kl<=MAX && DK*(kl-k)>0 && a*item[k]>=a*item[kl]) kl-=DK; //Swap the value of a[k] with that of a[l]. s = item[k]; item[k] = item[kl]; item[kl] = s; //Reverse the sequence from a[k + 1] up to and including the final element a[n]. l = k+DK; r = k0; while (MIN<=l && l<=MAX && MIN<=r && r<=MAX && DK*(r-l)>0) { s = item[l]; item[l] = item[r]; item[r] = s; fixed = fixed || (da*l+db === item[l]) || (da*r+db === item[r]); l+=DK; r-=DK; } if ("derangement" === type) { if (MIN<=kl && kl<=MAX) fixed = fixed || (da*kl+db === item[kl]); if (MIN<=r && r<=MAX) fixed = fixed || (da*r+db === item[r]); // TODO: find a way check for fixed without looping over the range here for (fixed=fixed||(da*k+db === item[k]),l=k-DK; !fixed && MIN<=l && l<=MAX; l-=DK) fixed = da*l+db === item[l]; } else { fixed = false; } } //else last item else item = null; // every 2-3 permutations is derangement on average, ie p(D) = 1/e } while (item && fixed); } } return item; } // https://en.wikipedia.org/wiki/Combinations // Unordered Combinations(Combinations), Ordered Combinations(Variations), Repeated Combinations, Ordered Repeated Combinations(Repeated Variations) Combination = Abacus.Combination = Class(CombinatorialIterator, { // extends and implements CombinatorialIterator constructor: function Combination(n, k, $) { var self = this, sub = null; if (!is_instance(self, Combination)) return new Combination(n, k, $); if (is_array(n) || is_args(n)) { $ = k || {}; k = n[1]||0; n = n[0]||0; } else { $ = $ || {}; n = n||0; k = k||0; } $.type = String($.type || "combination").toLowerCase(); if (-1 < $.type.indexOf('+')) { var a = $.type.split('+'); a.sort(); $.type = a.join('+'); } if (is_instance(k, CombinatorialIterator)) { sub = k; k = sub.dimension(); } else if (is_instance(n, CombinatorialIterator)) { sub = n; n = sub.base(); } else { sub = $.sub; } $.base = n; $.dimension = stdMath.max(0, k); if ("binary"===$.output) $.output = function(item,n){ return Combination.toBinary(item,n[0]); }; else if ("conjugate"===$.output) $.output = function(item,n){ return Combination.toComplement(item,n[0]); }; CombinatorialIterator.call(self, "Combination", [n, k], $, sub?{method:$.submethod,iter:sub,pos:$.subpos,cascade:$.subcascade}:null); } ,__static__: { C: CombinatorialIterator.C ,P: CombinatorialIterator.P ,T: CombinatorialIterator.T ,DUAL: CombinatorialIterator.DUAL ,count: function(n, $) { var type = $ && $.type ? $.type : "combination"/*"unordered"*/; return 0>n[0] || 0>n[1] ? Abacus.Arithmetic.O : (("ordered+repeated" === type) || ("variation+repeated" === type) || ("repeated+variation" === type) ? ( exp(n[0], n[1]) ) : (("repeated" === type) || ("combination+repeated" === type) ? ( factorial(n[0]+n[1]-1, n[1]) ) : (("ordered" === type) || ("variation" === type) ? ( factorial(n[0], -n[1]) ) : ( factorial(n[0], n[1]) )))); } ,initial: function(n, $, dir) { // some C-P-T dualities, symmetries & processes at play here // last (0>dir) is C-symmetric of first (0 n[0] || 0 > n[1]) return null; if (0===n[1]) return []; dir = -1 === dir ? -1 : 1; if ((!(COLEX&order) && (REVERSED&order)) || ((COLEX&order) && !(REVERSED&order))) dir = -dir; // O(k) item = ("repeated+variation" === type) || ("variation+repeated" === type) || ("ordered+repeated" === type) || ("combination+repeated" === type) || ("repeated" === type) ? ( 0 > dir ? array(n[1], n[0]-1, 0) : array(n[1], 0, 0) ) : (("ordered" === type) || ("variation" === type) ? ( 0 > dir ? array(n[1], n[0]-1, -1) : array(n[1], 0, 1) ) : ( 0 > dir ? array(n[1], n[0]-n[1], 1) : array(n[1], 0, 1) )); item = klass.DUAL(item, n, $); return item; } ,valid: function(item, n, $) { var klass = this, type = $ && $.type ? $.type : "combination"/*"unordered"*/, k = n[1], N, i, x, dict; if (!item || 0 > n[0] || 0 > n[1] || k !== item.length) return false; item = klass.DUAL(item.slice(), n, $); if (("ordered+repeated" === type) || ("variation+repeated" === type) || ("repeated+variation" === type)) { N = n[0]; for (i=0; i item[i] || item[i] >= N) return false; } } else if (("repeated" === type) || ("combination+repeated" === type)) { N = n[0]; for (i=0; i item[i] || item[i] >= N || (i+1 item[i+1])) return false; } } else if (("ordered" === type) || ("variation" === type)) { N = n[0]; for (dict={},i=0; i item[i] || item[i] >= N || 1 === dict[item[i]]) return false; dict[item[i]] = 1; } } else//if (("combination" === type) || ("unordered" === type) || ("binary" === type)) { N = n[0]; for (i=0; i item[i] || item[i] >= N || (i+1= item[i+1])) return false; } } return true; } ,succ: function(item, index, n, $, dir, CI) { if (!n || !n[0] || (0 >= n[0]) || (0>=n[1]) || (null == item)) return null; dir = -1 === dir ? -1 : 1; return next_combination(item, n, dir, $ && $.type ? $.type : "combination"/*"unordered"*/, $ && null!=$.order ? $.order : LEX, CI); } ,rand: function(n, $) { var klass = this, type = $ && $.type ? $.type : "combination"/*"unordered"*/, item, i, k = n[1], n_k, c, selected, rndInt = Abacus.Math.rndInt; if (0 > n[0] || 0 > n[1]) return null; if (0===k) return []; n = n[0]; n_k = n-k; c = n-1; // O(klogk) worst/average-case, unbiased if (("repeated" === type) || ("combination+repeated" === type) || ("ordered+repeated" === type) || ("variation+repeated" === type) || ("repeated+variation" === type)) { // p ~ 1 / n^k (ordered+repeated), p ~ 1 / binom(n+k-1,k) (repeated) item = 1 === k ? [rndInt(0, c)] : array(k, function(){return rndInt(0, c);}); if ((1 < k) && (("repeated" === type) || ("combination+repeated" === type))) mergesort(item, 1, true); } else if (("ordered" === type) || ("variation" === type)) { // p ~ 1 / k!binom(n,k) = 1 / n*(n-1)*..*(n-k+1) selected = {}; item = 1 === k ? ( [rndInt(0, c)] ) : (n === k ? ( shuffle(array(k, 0, 1)) ) : ( array(k, function(){ // select uniformly without repetition var selection = rndInt(0, c); // this is NOT an O(1) look-up operation, in general while (1 === selected[selection]) selection = (selection+1)%n; selected[selection] = 1; return selection; }) )); } else//if (("combination" === type) || ("unordered" === type) || ("binary" === type)) { // p ~ 1 / binom(n,k) selected = {}; item = 1 === k ? ( [rndInt(0, c)] ) : (n === k ? ( array(k, 0, 1) ) : (n_k < k ? ( complement(n, array(n_k, function(){ // select uniformly without repetition var selection = rndInt(0, c); // this is NOT an O(1) look-up operation, in general while (1 === selected[selection]) selection = (selection+1)%n; selected[selection] = 1; return selection; }),true) ) : ( mergesort(array(k, function(){ // select uniformly without repetition var selection = rndInt(0, c); // this is NOT an O(1) look-up operation, in general while (1 === selected[selection]) selection = (selection+1)%n; selected[selection] = 1; return selection; }),1,true) ))); } item = klass.DUAL(item, n, $); return item; } // random unranking, another method for unbiased random sampling ,randu: CombinatorialIterator.rand ,rank: function(item, n, $) { var klass = this, Arithmetic = Abacus.Arithmetic, add = Arithmetic.add, sub = Arithmetic.sub, mul = Arithmetic.mul, O = Arithmetic.O, I = Arithmetic.I, J = Arithmetic.J, index = O, i, c, j, k = n[1], N, binom, x, dict, order = $ && null!=$.order ? $.order : LEX, type = $ && $.type ? $.type : "combination"/*"unordered"*/; if (!item || 0 > n[0] || 0 > n[1] || k !== item.length) return J; if (0===k) return O; item = klass.DUAL(item, n, $); if (("ordered+repeated" === type) || ("variation+repeated" === type) || ("repeated+variation" === type)) { // O(k) N = n[0]; for (i=0; i item[i] || item[i] >= N) return J; index = add(mul(index, N), item[i]); } } else if (("repeated" === type) || ("combination+repeated" === type)) { // O(k) N = n[0]+k-1; binom = $ && $.count ? $.count : factorial(N, k); for (i=1; i<=k; i++) { // "Algorithms for Unranking Combinations and Other Related Choice Functions", Zbigniew Kokosi´nski 1995 (http://riad.pk.edu.pl/~zk/pubs/95-1-006.pdf) // adjust the order to match MSB to LSB // reverse of wikipedia article http://en.wikipedia.org/wiki/Combinatorial_number_system if (0 > item[i-1] || item[i-1] >= n[0] || (i item[i])) return J; c = N-1-item[i-1]-i+1; j = k+1-i; if (j <= c) index = add(index, factorial(c, j)); } index = sub(sub(binom,I),index); } else if (("ordered" === type) || ("variation" === type)) { // "Efficient Algorithms to Rank and Unrank Permutations in Lexicographic Order", Blai Bonet (http://ldc.usb.ve/~bonet/reports/AAAI08-ws10-ranking.pdf) // rank(ordered) = rank(k-n-permutation) // O(klgk) N = n[0]; for (dict={},i=0; i item[i] || item[i] >= N || 1 === dict[item[i]]) return J; dict[item[i]] = 1; } item = permutation2inversion(null, item, N); for (i=0; i item[i-1] || item[i-1] >= N || (i= item[i])) return J; c = N-1-item[i-1]; j = k+1-i; if (j <= c) index = add(index, factorial(c, j)); } index = sub(sub(binom,I),index); } if ((!(COLEX&order) && (REVERSED&order)) || ((COLEX&order) && !(REVERSED&order))) index = sub($ && null!=$.last?$.last:sub(klass.count(n, $),I), index); return index; } ,unrank: function(index, n, $) { var klass = this, Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, I = Arithmetic.I, sub = Arithmetic.sub, div = Arithmetic.div, mod = Arithmetic.mod, mul = Arithmetic.mul, lte = Arithmetic.lte, gt = Arithmetic.gt, val = Arithmetic.val, item, binom, k = n[1], N, m, t, p, type = $ && $.type ? $.type : "combination"/*"unordered"*/, repeated, order = $ && null!=$.order ? $.order : LEX; index = null == index ? null : Arithmetic.num(index); if (null==index || !Arithmetic.inside(index, Arithmetic.J, $ && null!=$.count ? $.count : klass.count(n, $))) return null; if (0 > n[0] || 0 > n[1]) return null; if (0===k) return []; if ((!(COLEX&order) && (REVERSED&order)) || ((COLEX&order) && !(REVERSED&order))) index = sub($ && null!=$.last?$.last:sub(klass.count(n, $),Arithmetic.I), index); n = n[0]; item = array(k); if (("ordered+repeated" === type) || ("variation+repeated" === type) || ("repeated+variation" === type)) { // O(k) for (m=index,p=k-1; p>=0; p--) { t = mod(m, n); m = div(m, n); item[p] = val(t); } } else if (("ordered" === type) || ("variation" === type)) { // "Efficient Algorithms to Rank and Unrank Permutations in Lexicographic Order", Blai Bonet (http://ldc.usb.ve/~bonet/reports/AAAI08-ws10-ranking.pdf) // unrank(ordered) = unrank(k-n-permutation) // O(klgk) for (m=index,p=k-1; p>=0; p--) { N = n-p; t = mod(m, N); m = div(m, N); item[p] = val(t); } inversion2permutation(item, item, N); } else//if (("repeated" === type) || ("combination+repeated" === type) || ("combination" === type) || ("unordered" === type) || ("binary" === type)) { // "Algorithms for Unranking Combinations and Other Related Choice Functions", Zbigniew Kokosi´nski 1995 (http://riad.pk.edu.pl/~zk/pubs/95-1-006.pdf) // adjust the order to match MSB to LSB // O(k) repeated = ("repeated" === type) || ("combination+repeated" === type); N = repeated ? n+k-1 : n; binom = $ && $.count ? $.count : factorial(N, k); index = sub(sub(binom,I),index); binom = div(mul(binom,N-k),N); t = N-k+1; m = k; p = N-1; do { if (lte(binom, index)) { item[k-m] = repeated ? N-t-k+1 : N-t-m+1; if (gt(binom, O)) { index = sub(index, binom); binom = div(mul(binom,m),p); } m--; p--; } else { binom = div(mul(binom,p-m),p); t--; p--; } } while (m > 0); } n = [n, k]; item = klass.DUAL(item, n, $); return item; } ,toComplement: function(alpha, n, ordered) { return true === ordered ? shuffle(complement(n, alpha, true)) : complement(n, alpha); } ,toBinary: function(item, n) { return subset2binary(item, n); } ,fromBinary: function(item, n) { return binary2subset(item, n); } ,pick: function(a, k, type) { 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)) : []; } ,choose: function(arr, comb) { return comb && comb.length ? array(comb.length, function(i){ return 0<=comb[i] && comb[i] N[0] || 0 > N[1]) return null; // some C-P-T dualities, symmetries & processes at play here // LEX MIN = 0; MAX = k-1; DI = 1; i0 = MAX; a = 1; b = 0; da = 1; db = 0; if (COLEX & order) { //CP-symmetric of LEX a = -a; b = n-1-b; DI = -DI; i0 = MAX-i0; da = -da; db = MAX-db; } if (REFLECTED & order) { //P-symmetric of LEX DI = -DI; i0 = MAX-i0; da = -da; db = MAX-db; } if (REVERSED & order) { //T-symmetric of LEX dir = -dir; } // constant average delay (CAT) for ordered+repeated (=tuple) // constant average delay (CAT) for ordered (or linear if "CI" map is computed at run-time) // constant average delay (CAT) for unordered(repated or not) (or linear if "CI" map is computed at run-time) if (0 > dir) { // compute prev indexes // find index to move if (("ordered+repeated" === type) || ("variation+repeated" === type) || ("repeated+variation" === type)) { i = i0; while ((MIN<=i && i<=MAX) && (item[i] === 0)) i-=DI; if (MIN<=i && i<=MAX) for (n=n-1,item[i]=item[i]-1,j=i+DI; MIN<=j && j<=MAX; j+=DI) item[j] = n; //else last item else item = null; } else if (("ordered" === type) || ("variation" === type)) { if (null == CI) CI = comb_item_(item, n, k, order, type); i = i0; index = -1; while (-1===index && MIN<=i && i<=MAX) { if (a*item[i]+b-a >= 0 ) { for (j=a*item[i]+b-a; 0<=j && j 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 { /*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 n ? Abacus.Arithmetic.O : pow2(n); } ,initial: function(n, $, dir) { // some C-P-T dualities, symmetries & processes at play here // last (0>dir) is C-symmetric of first (0 n) return null; dir = -1 === dir ? -1 : 1; if (REVERSED&order) dir = -dir; // O(n) // fixed-length item, with effective length as extra last pos item = []; if (0 < n) { if ((("binary" === type) || (COLEX & order)) && !(MINIMAL & order)) { //item = 0 > dir ? array(n, 0, 1) : []; if (0>dir) item = array(n, 0, 1); } else { if (0>dir) item = [n-1]; } } item = klass.DUAL(item, n, $, 1); return item; } ,valid: function(item, n, $) { var klass = this, is_binary = "binary" === ($||{}).type, i, x, l, dict; if (!item || 0>n) return false; item = klass.DUAL(item.slice(), n, $, -1); if (0 > item.length || n < item.length) return false; if (is_binary) { l = item.length; dict = {}; for (i = 0; i < l; i++) { x = item[i]; if (0 > x || x >= n || 1 === dict[x] || (i+1 x || x >= n || 1 === dict[x] || (i+1= item[i+1])) return false; dict[x] = 1; } } return true; } ,succ: function(item, index, n, $, dir, SI) { if (null == item) return null; var klass = this, Arithmetic = Abacus.Arithmetic, i, item, count, type = $ && $.type ? $.type : "subset", order = $ && null != $.order ? $.order : LEX; if (0 >= n) return null; if (MINIMAL & order) { if (null != index) { count = null != $.count ? $.count : klass.count(n, $); index = Arithmetic.add(index, 0>dir?Arithmetic.J:Arithmetic.I); if (Arithmetic.inside(index, Arithmetic.J, count)) { if (REVERSED & order) index = Arithmetic.sub(Arithmetic.sub(count, Arithmetic.I), index); index = grayn(index); // O(n) i = 0; item = new Array(n+1); item[n] = 0; while (i n) return null; // p ~ 1 / 2^n, O(n) for (var list = null,i=n-1; i>=0; i--) if (rndInt(0,1)) list = {len:list?list.len+1:1, k:i, next:list}; item = list ? array(list.len, function(i){var k = list.k; list = list.next; return k;}): []; // fixed-length item, with effective length as extra last pos //if (!$ || "binary" !== $.type) //item = item.concat(item.lengthn) return J; item = klass.DUAL(item, n, $, -1); if (n+1===item.length) { item = (is_binary && !is_reflected) || (is_reflected && !is_binary) ? item.slice(n-item[n],n) : item.slice(0,item[n]); } if ($.mindimension > item.length || $.maxdimension < item.length) return J; if (0 === n) { index = O; } else if (MINIMAL & order) { // O(n) l = item/*[n]*/.length; dict = {}; for (index = O,i = 0; i < l; i++) { x = item[i]; if (0 > x || x >= n || 1 === dict[x] || (i+1= item[i+1])) return J; index = add(index, subset_bin_rank(n, x)); dict[x] = 1; } index = igrayn(index); if (REVERSED&order) index = sub($ && null!=$.last?$.last:sub(klass.count(n, $), I), index); } else if (COLEX & order) { // O(n) l = item/*[n]*/.length; dict = {}; for (index = O,i = 0; i < l; i++) { x = item[i]; if (0 > x || x >= n || 1 === dict[x] || (i+1= item[i+1])) return J; index = add(index, subset_bin_rank(n, x)); dict[x] = 1; } if (REVERSED & order) index = sub($ && null!=$.last?$.last:sub(klass.count(n, $), I), index); } else if (is_binary) { // O(n) l = item/*[n]*/.length; dict = {}; for (index = O,i = 0; i < l; i++) { x = item[i]; if (0 > x || x >= n || 1 === dict[x] || (i+1 x || x >= n || 1 === dict[x] || (i+1= item[i+1])) return J; index = add(index, subset_lex_rank(n, x, y)); dict[x] = 1; y = x; } if (REVERSED & order) index = sub($ && null!=$.last?$.last:sub(klass.count(n, $), I), index); } return index; } ,unrank: function(index, n, $) { var klass = this, Arithmetic = Abacus.Arithmetic, O = Arithmetic.O, I = Arithmetic.I, band = Arithmetic.band, shr = Arithmetic.shr, gt = Arithmetic.gt, add = Arithmetic.add, sub = Arithmetic.sub, gte = Arithmetic.gte, type = $ && $.type ? $.type : "subset", order = $ && null!=$.order ? $.order : LEX, count = $ && null!=$.count ? $.count : klass.count(n, $), item, i, j, y, c = O, c0; index = null == index ? null : Arithmetic.num(index); if (!$ || 0 > n || null==index || !Arithmetic.inside(index, Arithmetic.J, count)) return null; item = new Array(n+1)/*[]*/; item[n] = 0; if (0 < n) { if (MINIMAL & order) { if (REVERSED&order) index = sub($ && null!=$.last?$.last:sub(count, I), index); index = grayn(index); // O(n) i = 0; while (i= N) return null; // some C-P-T dualities, symmetries & processes at play here // LEX DI = 1; a = 1; b = 0; if (COLEX & order) { //CP-symmetric of LEX /* a = -a; b = MAX-b; DI = -DI; //dir = -dir; */ return null; } if (REFLECTED & order) { //P-symmetric of LEX DI = -DI; } if (REVERSED & order) { //T-symmetric of LEX dir = -dir; } if (0 > DI) { IMIN = N-(item[LEN]||1); IMAX = N-1; i0 = IMAX; i1 = IMIN; } else { IMIN = 0; IMAX = item[LEN]-1; i0 = IMIN; i1 = IMAX; } // loopless, item is of fixed dimensions n+1, with effective length item[LEN] as extra last pos (ie N) // NOTE: effective item = item.slice(0,item[LEN]) or item.slice(N-item[LEN],N) if reflected if (0 > dir) { // NOTE: colex+reversed does not work if (0 < item[LEN]) { t = item[i1]; if (t > MIN) { if (1 === item[LEN] || t>item[i1-DI]+1) { // extend item[i1] -= 1; item[i1+DI] = MAX; item[LEN]++; } else { // reduce item[LEN]--; } } else { // empty item[LEN] = 0; } } else item = null; } else { // adapted from "Generating All and Random Instances of a Combinatorial Object", Ivan Stojmenovic (http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.211.6576) if (0 === item[LEN]) { // empty item[IMIN] = a*MIN+b; item[LEN] = 1; } else if (a*item[i0]+b < MAX) { if (a*item[i1]+b < MAX) { // extend item[i1+DI] = item[i1]+a; item[LEN]++; } else { // reduce item[i1-DI] += a; item[LEN]--; } } // last else item = null; } return item; } // https://en.wikipedia.org/wiki/Partitions // https://en.wikipedia.org/wiki/Composition_(combinatorics) // integer compositions (resp. restricted k-compositions) have bijections ("isomorphisms") to subsets (resp. k-subsets=combinations) // via "partial-sums mapping": x_1=y_1,..,x_k=y_k-y_{k-1},..,x_m (composition) ::=> y_1=x_1,..,y_k=y_{k-1}+x_k,..,y_m (subset) Partition = Abacus.Partition = Class(CombinatorialIterator, { // extends and implements CombinatorialIterator constructor: function Partition(n, $) { var self = this, sub = null, M, W, K, k1, k0; if (!is_instance(self, Partition)) return new Partition(n, $); $ = $ || {}; $.type = $.type || "partition"; n = n||0; if (is_instance(n, CombinatorialIterator)) { sub = n; n = sub.base(); } else { sub = $.sub; } M = null!=$["max="] ? $["max="]|0 : null; W = null!=$["min="] ? $["min="]|0 : null; K = null!=$["parts="] ? $["parts="]|0 : null; k1 = null!=K ? K : (null!=W && null!=M ? (M===W ? stdMath.ceil(n/W) : stdMath.max(1, stdMath.ceil((n-M)/W))+1) : (null!=W ? stdMath.ceil(n/W) : (null!=M ? stdMath.max(0, n-M)+1 : n))); k0 = null!=K ? K : (null!=W && null!=M ? (M===W ? stdMath.ceil(n/M) : stdMath.max(1, stdMath.ceil((n-W)/M))+1) : (null!=W ? 2 : (null!=M ? stdMath.ceil(n/M) : 1))); $.base = n; $.mindimension = stdMath.max(1, stdMath.min(k0, k1)); $.maxdimension = stdMath.max(1, stdMath.max(k0, k1)); $.dimension = $.maxdimension; $.rand = $.rand || {}; if ("conjugate"===$.output) $.output = function(item,n){ return conjugatepartition(0, item, (REFLECTED&$.order)&&!(COLEX&$.order) || (COLEX&$.order)&&!(REFLECTED&$.order) ? -1 : 1); }; else if ("subset"===$.output) $.output = function(item,n){ return Partition.toSubset(item); }; else if ("packed"===$.output) $.output = function(item,n){ return Partition.toPacked(item); }; CombinatorialIterator.call(self, "Partition", n, $, sub?{method:$.submethod,iter:sub,pos:$.subpos,cascade:$.subcascade}:null); } ,__static__: { C: function(item, N, LEN, $, dir) { // C process / symmetry, ie Rotation/Complementation/Conjugation, CC = I var klass = this, is_composition = "composition" === ($ && $.type ? $.type : "partition"), M = $ && null!=$["max="] ? $["max="]|0 : null, W = $ && null!=$["min="] ? $["min="]|0 : null, K = $ && null!=$["parts="] ? $["parts="]|0 : null, reflected = -1===dir, itemlen; if (null != K || null != M || null != W) return item; // TODO if (LEN+1===item.length) { item = reflected ? item.slice(LEN-item[LEN][0],LEN) : item.slice(0,item[LEN][0]); item = conjugatepartition(is_composition, item, dir); itemlen = item.length; if (itemlen n) { return O; } else if (0 === n) { return (null == K || 0 < K) && (null == M || 0 === M) && (null == W || 0 === W) ? Arithmetic.I : O; } else { return "composition"===type ? compositions(n, K, M, W) : partitions(n, K, M, W); } } ,initial: function(n, $, dir) { // some C-P-T dualities, symmetries & processes at play here // last (0>dir) is C-symmetric of first (0 n) || (null!=K && null!=M && null!=W && ((0 >= K) || (0 >= W) || (0 >= M) || (W > M) || (K*W+M > n+W) || (K*M+W < n+M))) || (null!=M && null!=W && ((0 >= M) || (0 >= W) || (W > M) || (M > n) || (W > n) || (M === W && 0 !== n % M) || (M !== W && (M+W > n || (M+W < n && n-(M+W) < W))))) || (null!=K && null!=W && ((0 >= K) || (0 >= W) || /*(W+(K-1)*(n-W) < n) ||*/ (K*W > n))) || (null!=K && null!=M && ((0 >= K) || (0 >= M) || (K+M > n+1) || (K*M < n))) || (null!=W && (0 >= W || W > n || (W < n && W+W > n))) || (null!=M && (0 >= M || M > n)) || (null!=K && (0 >= K || K > n)) ) { return null; } else { dir = -1 === dir ? -1 : 1; if ((!(COLEX&order) && (REVERSED&order)) || ((COLEX&order) && !(REVERSED&order))) dir = -dir; // O(n) item = new Array(LEN+1); item[LEN] = [0,0,0]; if (K && M && W) { // restricted partition n into exactly K parts with min part=W and max part=M item[LEN][0] = K; if (M === W) { item = K*M === n ? operate(function(item,ai,i){ item[i] = M; item[LEN][1]++; item[LEN][2]++; return item; }, item, null, 0,K-1,1) : null; } else { if (1 >= K || n < W+M) return null; if (is_composition) { m = n-W-M-(2 < K ? W*(K-2) : 0); item[0] = M; item[LEN][1]++; item = operate(function(item,ai,i){ item[i] = stdMath.min(M, W+m); m -= item[i]-W; if (M === item[i]) item[LEN][1]++; if (W === item[i]) item[LEN][2]++; return item; }, item, null, 1,K-2,1); item[K-1] = W; item[LEN][2]++; if (0 < dir) reflection(item,item,K,0,K-1); } else if (0 > dir) { m = n-W-M-(2 < K ? W*(K-2) : 0); item[0] = M; item[LEN][1]++; item = operate(function(item,ai,i){ item[i] = stdMath.min(M, W+m); m -= item[i]-W; if (M === item[i]) item[LEN][1]++; if (W === item[i]) item[LEN][2]++; return item; }, item, null, 1,K-2,1); item[K-1] = W; item[LEN][2]++; } else { m = stdMath.max(W, stdMath.min(M, 2 < K ? stdMath.floor((n-M-W)/(K-2)) : n-M-W)); k = 2 < K ? (n-M-W)%(K-2) : 0; item = operate(function(item,ai,i){ item[i] = 0===i ? M : (K-1===i ? W : (i-1 dir) { k = stdMath.floor((n-W)/M); if (0 >= k) return null; m = n-W-k*M; if (0 < m && m < W) { k--; m += M-W; item[LEN][0] = k+1+(0 < m); } else { item[LEN][0] = k+1+(0 < m); } item = operate(function(item,ai,i){ if (i < k) { item[i] = M; item[LEN][1]++; } else if (i === k && 0 < m) { item[i] = m; if (m === M) item[LEN][1]++; if (m === W) item[LEN][2]++; } else { item[i] = W; item[LEN][2]++; } return item; }, item, null, 0,item[LEN][0]-1,1); } else { k = stdMath.floor((n-M)/W); if (0 >= k) return null; m = n-M-k*W; l = stdMath.max(1, stdMath.floor(m/k)); item[LEN][0] = k+1; item = operate(function(item,ai,i){ if (0 === i) { item[i] = M; item[LEN][1]++; } else if (0 < m) { item[i] = W+l; if (item[i] === M) item[LEN][1]++; if (item[i] === W) item[LEN][2]++; m -= l; } else { item[i] = W; item[LEN][2]++; } return item; }, item, null, 0,item[LEN][0]-1,1); if (is_composition) reflection(item,item,item[LEN][0],0,item[LEN][0]-1); } } } else if (K && W) { item[LEN][0] = K; // restricted partition n into exactly K parts with min part=W if (1 === K) { if (n !== W) return null; item[0] = W; item[LEN][2] = 1; } if (is_composition) { k = K-1; m = n-k*W; item = operate(function(item,ai,i){ item[i] = W; item[LEN][2]++; return item; }, item, null, 1,K-1,1); item[0] = m; if (W === m) item[LEN][2]++; if (0 < dir) reflection(item,item,K,0,K-1); } else if (0 > dir) { k = K-1; m = n-k*W; item = operate(function(item,ai,i){ item[i] = W; item[LEN][2]++; return item; }, item, null, 1,K-1,1); item[0] = m; if (W === m) item[LEN][2]++; } else { m = stdMath.max(W, 1 < K ? stdMath.floor((n-W)/(K-1)) : n-W); k = 1 < K ? (n-W)%(K-1) : 0; item = operate(function(item,ai,i){ item[i] = i dir) reflection(item,item,K,0,K-1); } else if (0 > dir) { m = n; item = operate(function(item,ai,i){ item[i] = stdMath.min(M, m-(K-i-1)); if (M === item[i]) item[LEN][1]++; m -= item[i]; return item; }, item, null, 0,K-1,1); } else { m = stdMath.min(M, 1 < K ? stdMath.floor((n-M)/(K-1)) : n-M); k = 1 < K ? (n-M)%(K-1) : 0; item = operate(function(item,ai,i){ item[i] = 0===i ? M : (i-1 dir) reflection(item,item,K,0,K-1); } else { m = stdMath.floor(n/K); k = n%K; item = operate(function(item,ai,i){ item[i] = 0 > dir ? (0===i ? n-K+1 : 1) : (m+(i dir ? [n-K+1].concat(array(K-1, 1, 0)) : array(K, function(i){return m+(i dir) { item[LEN][0] = 2; item[0] = n-W; item[1] = W; item[LEN][2] = 1 + (W===item[0] ? 1 : 0); } else if (is_composition) { k = stdMath.floor(n/W); m = n-k*W; if (0 < m && W > m) { k--; m += W; item[LEN][0] = k+1; } else { item[LEN][0] = k+(0 < m); } item = operate(function(item,ai,j){ if (j < k) { item[j] = W; item[LEN][2]++; } else { item[j] = m; if (W === m) item[LEN][2]++; } return item; }, item, null, 0,item[LEN][0]-1,1); } else { k = stdMath.floor(n/W); m = n-k*W; if (1 < k) { l = stdMath.floor(m/(k-1)); i = m%(k-1); } else { l = 0; i = 0; } item[LEN][0] = k; item = operate(function(item,ai,j){ if (0 < m) { item[j] = W+l; m -= l; if (0 < i) { item[j]++; i--; m--; } if (W === item[j]) item[LEN][2]++; } else { item[j] = W; item[LEN][2]++; } return item; }, item, null, 0,item[LEN][0]-1,1); } } else if (M) { // restricted partition n into parts with largest part=M // equivalent to conjugate to partition n into exactly M parts k = stdMath.floor(n/M); m = n%M; if (is_composition) { item = operate(function(item,ai,i){ item[i] = ai; item[LEN][0]++; if (M === item[i]) item[LEN][1]++; return item; }, item, 0 > dir ? array(k, M, 0).concat(m?[m]:[]) : array(n-M, 1, 0).concat([M])); } else { item = operate(function(item,ai,i){ item[i] = ai; item[LEN][0]++; if (M === item[i]) item[LEN][1]++; return item; }, item, 0 > dir ? array(k, M, 0).concat(m?[m]:[]) : [M].concat(array(n-M, 1, 0))); } } else { // unrestricted partition/composition item = operate(function(item,ai,i){ item[i] = ai; item[LEN][0]++; return item; }, item, 0 > dir ? [n] : array(n, 1, 0)); } } if (item) item = item.slice(0, item[LEN][0]); } item = klass.DUAL(item, n, $, 1); return item; } ,valid: function(item, n, $) { var klass = this, type = $ && $.type ? $.type : "partition", M = $ && null!=$["max="] ? $["max="]|0 : null, W = $ && null!=$["min="] ? $["min="]|0 : null, K = $ && null!=$["parts="] ? $["parts="]|0 : null, i, l, x, k0, k1, d0, d1; if ( !item || !item.length || (0 > n) || (null!=K && null!=M && null!=W && ((0 >= K) || (0 >= W) || (0 >= M) || (W > M) || (K*W+M > n+W) || (K*M+W < n+M))) || (null!=M && null!=W && ((0 >= M) || (0 >= W) || (W > M) || (M > n) || (W > n) || (M === W && 0 !== n % M) || (M !== W && (M+W > n || (M+W < n && n-(M+W) < W))))) || (null!=K && null!=W && ((0 >= K) || (0 >= W) || K*W > n)) || (null!=K && null!=M && ((0 >= K) || (0 >= M) || (K+M > n+1) || (K*M < n))) || (null!=W && (0 >= W || W > n || (W < n && W+W > n))) || (null!=M && (0 >= M || M > n)) || (null!=K && (0 >= K || K > n)) ) return false; k1 = null!=K ? K : (null!=W && null!=M ? (M===W ? stdMath.ceil(n/W) : stdMath.max(1, stdMath.ceil((n-M)/W))+1) : (null!=W ? stdMath.ceil(n/W) : (null!=M ? stdMath.max(0, n-M)+1 : n))); k0 = null!=K ? K : (null!=W && null!=M ? (M===W ? stdMath.ceil(n/M) : stdMath.max(1, stdMath.ceil((n-W)/M))+1) : (null!=W ? 2 : (null!=M ? stdMath.ceil(n/M) : 1))); d0 = stdMath.max(1, stdMath.min(k0, k1)); d1 = stdMath.max(1, stdMath.max(k0, k1)); if (d0 > item.length || d1 < item.length) return false; item = klass.DUAL(item.slice(), n, $, -1); if ("composition" === type) { if (null!=W && M === W) { return (null == K || n === K*M) && 0 === item.filter(function(x){return x !== M;}).length ? true : false; } for (i=0,l=item.length; i= x || x > n || (W && x < W) || (M && x > M)) return false; n -= x; } if (0 !== n) return false; } else { if (null!=W && M === W) { return (null == K || n === K*M) && 0 === item.filter(function(x){return x !== M;}).length ? true : false; } for (i=0,l=item.length; i= x || x > n || (W && x < W) || (M && x > M) || (i+1= x || x > n || (W && x < W) || (M && x > M)) return J; index = Arithmetic.add(index, W === x ? O : comp_rank(n, x, W, M, K ? K-i : null, w, m)); if (W === x) w++; if (M === x) m++; n -= x; } if (0 !== n || i !== item.length) return J; if (REVERSED & order) index = Arithmetic.sub(last, index); } else { index = last; if (W) { if (M === W) return (null == K || n === K*M) && 0 === item.filter(function(x){return x !== M;}).length ? O : J; n -= W; if (K) K--; } for (i=0; i= x || x > n || (W && x < W) || (M && x > M) || (i+1= x || (W && W > x)) break; if (W === x) w++; if (M === x) m++; item.push(x); index = Arithmetic.sub(index, c); n -= x; } } } else { if (W) { if (M === W) { item = null == K || stdMath.floor(n/M) === K ? array(stdMath.floor(n/M), M) : null; } else { n -= W; if (K) K--; } } if (M) { n -= M; if (K) K--; } if (item && !item.length) { for (i=0; 0= x || (W && W > x)) break; item.push(x); index = Arithmetic.sub(index, c); n -= x; } if (W) item.push(W); if (M) item.unshift(M); } } } item = klass.DUAL(item, n, $, 1); return item; } ,toConjugate: function(item, type) { return conjugatepartition("composition"===type, item); } ,toSubset: function(item) { return composition2subset(item); } ,fromSubset: function(item) { return subset2composition(item); } ,toPacked: function(item) { return packpartition(item); } ,fromPacked: function(item) { return unpackpartition(item); } } ,_update: function() { var self = this, $ = self.$, n = self.n, item = self.__item, type = $ && $.type ? $.type : "partition", order = $ && null!=$.order ? $.order : LEX, M = $ && null!=$["max="] ? $["max="]|0 : null, W = $ && null!=$["min="] ? $["min="]|0 : null, K = $ && null!=$["parts="] ? $["parts="]|0 : null, LEN = $.dimension, itemlen, x, y = 0, z = 0; if ((null != item) && (LEN+1 !== item.length)) { itemlen = item.length; item = item.slice(); if (null != M || null != W) { for (x=0,y=0,z=0; x= n || (null != K && 0 >= K) || (null != W && 0 >= W) || (null != M && 0 >= M)) return null; // some C-P-T dualities, symmetries & processes at play here // LEX /*if (COLEX & order) { //CP-symmetric of LEX dir = -dir; }*/ if (REFLECTED & order) { //P-symmetric of LEX DI = -DI; } if (REVERSED & order) { //T-symmetric of LEX dir = -dir; } if (0 > DI) { MIN = LN-(item[INFO][LEN]||1); MAX = LN-1; i0 = MAX; i1 = MIN; } else { MIN = 0; MAX = item[INFO][LEN]-1; i0 = MIN; i1 = MAX; } if (COLEX & order) { return null; // not implemented } if (0 > dir) { // compute prev partition if (K) { if (M && W && (M === W)) return null; // there is only one, if any l = M ? 1 : 0; r = W ? 1 : 0; w = W ? W : 1; rem = n-(M ? M : 0)-(W ? W : 0); m = 0 < K-l-r ? rem % (K-l-r) : 0; d = stdMath.min(M ? M : rem, 0 < K-l-r ? stdMath.floor(rem/(K-l-r)) : rem); k = 0; i = -1; for (j=i0+l*DI; MIN<=j-l*DI && j+r*DI<=MAX; j+=DI) { if ((w < item[j]) && (d+(k i-l*DI) { item = null; } else { if (M === item[i]) item[INFO][NMAX]--; item[i]--; if (W === item[i]) item[INFO][NMIN]++; i += DI; rem = 1; k = 0; j = i; while (MIN<=j-l*DI && j+r*DI<=MAX) {k++; rem += item[j]; j += DI;} while (0 w)) { i = i1; rem = 0; l = 0; r = 0; while ((MIN<=i && i<=MAX) && (DI*(i-j) >= 0) && (w === item[i])) { rem+=item[i]; if (M === item[i]) l++; if (W === item[i]) r++; i-=DI; } if (M === item[i]) item[INFO][NMAX]--; m = item[i]-1; rem++; item[i] = m; item[INFO][LEN] = (0 > DI ? LN-i : i+1) + (W ? 1 : 0); item[INFO][NMAX] -= l; item[INFO][NMIN] -= r; if (W === item[i]) item[INFO][NMIN]++; if (m < rem) { j = rem % m; rem = stdMath.floor(rem/m); while (0 < rem--) { i+=DI; item[i] = m; item[INFO][LEN]++; if (M === item[i]) item[INFO][NMAX]++; if (W === item[i]) item[INFO][NMIN]++; } rem = j; } if (w <= rem) { i+=DI; item[i] = rem; rem = 0; item[INFO][LEN]++; if (M === item[i]) item[INFO][NMAX]++; if (W === item[i]) item[INFO][NMIN]++; } if (0 < rem) { return null; } if (W) { i+=DI; item[i] = W; } } // if partition is all ones (so first element is also one) it is the final partition //else last item else item = null; } } else { // compute next partition if (K) { if (M && W && (M === W)) return null; // there is only one, if any if (W) { w = W; i = i1-DI; } else { w = 1; i = i1; } rem = 0; k = 0; while (MIN <= i && i <= MAX && w === item[i]) {rem += item[i]; k++; i -= DI;} if (i < MIN || i > MAX) { item = null; } else { if (M === item[i]) item[INFO][NMAX]--; if (W === item[i]-1) item[INFO][NMIN]++; item[i]--; rem += item[i]; k++; i -= DI; if (i < MIN || i > MAX) { item = null; } else { while (MIN<=i && i<=MAX && ((M && M MAX) { item = null; } else { item[i]++; if (M === item[i]) item[INFO][NMAX]++; m = 0 < k ? rem % k : 0; d = 0 < k ? stdMath.floor(rem/k) : rem; j = 0; while (0 < rem) { i += DI; if (M === item[i]) item[INFO][NMAX]--; if (W === item[i]) item[INFO][NMIN]--; item[i] = d+(j k; j = i0+DI; } else if (W) { w = W; m = item[INFO][LEN] > 2 || item[i0]+W < n; j = i0; } else if (M) { w = 1; m = stdMath.min(M, n-M); k = stdMath.ceil(n/M)-1; m = /*MAX*/item[INFO][LEN] > k+1 || item[i0+(k-1)*DI] < m; j = i0+DI; } else { w = 1; m = item[i0] < n; j = i0; } if (MIN <= j && j <= MAX && m) { l = 0; r = 0; rem = 0; if (0 < MAX) { i = i1-DI; rem += item[i1]; if (M === item[i1]) l++; if (W === item[i1]) r++; } else { i = i1; } while ((MIN<=i && i<=MAX) && (MIN<=i-DI && i-DI<=MAX) && (DI*(i-j) > 0) && (item[i-DI] === item[i] || (W && (rem-1 < W)))) { rem += item[i]; if (M === item[i]) l++; if (W === item[i]) r++; i -= DI; } if (M && (M <= item[i])) return null; item[INFO][LEN] = (0 > DI ? LN-i : i+1); item[INFO][NMAX] -= l; item[INFO][NMIN] -= r; if (W === item[i]) item[INFO][NMIN]--; item[i]++; rem--; j = i; if (M === item[i]) item[INFO][NMAX]++; while (w <= rem) { i += DI; item[INFO][LEN]++; item[i] = w; rem -= w; if (W) item[INFO][NMIN]++; if (M === item[i]) item[INFO][NMAX]++; } if (0 < rem) { if (0 > DI) { MIN = LN-(item[INFO][LEN]||1); MAX = LN-1; } else { MIN = 0; MAX = item[INFO][LEN]-1; } i = j+DI; while (MIN<=i && i<=MAX && 0 < rem) { m = MIN<=i-DI && i-DI<=MAX ? (item[i-DI]>item[i] ? 1 : 0) : stdMath.min(M ? M-item[i] : rem, rem); if (W === item[i]) { if (1 === item[INFO][NMIN]) { i = j; while (MIN<=i && i<=MAX && MIN<=i-DI && i-DI<=MAX && item[i-DI]===item[i]) i -= DI; if (MIN<=i-DI && i-DI<=MAX) { item[i]++; rem--; i += DI; continue; } else { m = stdMath.min(M ? M-item[i] : rem, rem); item[i] += m; rem -= m; break; } } else { item[INFO][NMIN]--; } } item[i] += m; rem -= m; if (M === item[i]) item[INFO][NMAX]++; i += DI; } } if (0 < rem) item = null; } // if partition is the number itself it is the final partition //else last item else item = null; } } return item; } function next_composition(item, N, dir, K, M, W, LN, order, PI) { //maybe "use asm" var n = N, INFO = LN, LEN = 0, NMAX = 1, NMIN = 2, i, j, i0, i1, k, nn, m, w, d, l, r, rem, DI = 1, MIN, MAX; if (0 >= n || (null != K && 0 >= K) || (null != W && 0 >= W) || (null != M && 0 >= M)) return null; // some C-P-T dualities, symmetries & processes at play here // LEX /*if (COLEX & order) { //CP-symmetric of LEX dir = -dir; }*/ if (REFLECTED & order) { //P-symmetric of LEX DI = -DI; } if (REVERSED & order) { //T-symmetric of LEX dir = -dir; } if (0 > DI) { MIN = LN-(item[INFO][LEN]||1); MAX = LN-1; i0 = MAX; i1 = MIN; } else { MIN = 0; MAX = item[INFO][LEN]-1; i0 = MIN; i1 = MAX; } if (0 > dir) { // compute prev composition if (K) { if (M && W) { if (M === W) return null; // there is only one, if any if (COLEX & order) { item = null; } else { i = i1-DI; j = i1; d = item[i1]-W; rem = item[i1]; k = 1; while (MIN<=i && i<=MAX && (W===item[i] || M i || i > MAX) { item = null; } else { if (0 < d) { m = rem+1-W*(k-1); if (1 === item[INFO][NMIN] && W === item[j] && (k-1)*M+W < rem+1) { rem += item[i]-W; item[i] = W; item[INFO][NMIN]++; } else if (1 === item[INFO][NMAX] && M === item[i] && M > m) { item[i] = stdMath.max(item[j], item[i1]); rem += M-item[i]; if (M !== item[i]) item[INFO][NMAX]--; if (W === item[i]) item[INFO][NMIN]++; } else { if (M === item[i]) item[INFO][NMAX]--; rem++; item[i]--; if (W === item[i]) item[INFO][NMIN]++; } m = rem-W*k; while (0 < rem && MIN <= j && j <= MAX) { if (W === item[j]) item[INFO][NMIN]--; if (M === item[j]) item[INFO][NMAX]--; item[j] = stdMath.min(M, W+m); rem -= item[j]; m -= item[j]-W; if (M === item[j]) item[INFO][NMAX]++; if (W === item[j]) item[INFO][NMIN]++; j += DI; } } else { if (1 === item[INFO][NMIN] && W === item[j]) { item[j] = item[i]; item[i] = W; } else if (1 === item[INFO][NMAX] && M === item[i] && M > item[j]+1) { item[i] = item[j]; item[j] = M; } else { if (M === item[i]) item[INFO][NMAX]--; if (W === item[j]) item[INFO][NMIN]--; item[i]--; item[j]++; if (M === item[j]) item[INFO][NMAX]++; if (W === item[i]) item[INFO][NMIN]++; } } } } } else if (W) { if (COLEX & order) { item = null; } else { m = item[i1]; if (n-W*(K-1) > m) { i = i1-DI; while (MIN <= i && i <= MAX && W === item[i]) i-=DI; j = i+DI; if (1 === item[INFO][NMIN] && W === item[j] && j === i1) { item[j] = item[i]; item[i] = W; } else { if (W === item[j]) item[INFO][NMIN]--; item[i]--; item[i1] = W; item[j] = 1+m; if (W === item[i]) item[INFO][NMIN]++; if (item[i1] === W && W !== m) item[INFO][NMIN]++; } } // last else item = null; } } else if (M) { if (COLEX & order) { item = null; } else { i = i1-DI; j = i1; d = item[i1]-1; rem = item[i1]; k = 1; while (MIN<=i && i<=MAX && (1===item[i] || M i || i > MAX) { item = null; } else { if (0 < d) { if (1 === item[INFO][NMAX] && M === item[i] && M > rem-(k-1)+1) { item[i] = stdMath.max(item[j], item[i1]); rem += M-item[i]; if (M !== item[i]) item[INFO][NMAX]--; } else { if (M === item[i]) item[INFO][NMAX]--; item[i]--; rem++; } l = 0; while (0 < rem && MIN <= j && j <= MAX) { if (M === item[j]) item[INFO][NMAX]--; item[j] = stdMath.min(M, rem-(k-l-1)); rem -= item[j]; if (M === item[j]) item[INFO][NMAX]++; j += DI; l++; } } else { if (1 === item[INFO][NMAX] && M === item[i] && M > item[j]+1) { item[i] = item[j]; item[j] = M; } else { if (M === item[i]) item[INFO][NMAX]--; item[i]--; item[j]++; if (M === item[j]) item[INFO][NMAX]++; } } } } } else { // adapted from FXT lib if (COLEX & order) { m = item[i0]; if (n-K+1 > m) { item[i0] = 1; i = i0+DI; while (MIN <= i && i <= MAX && 1 === item[i]) i+=DI; item[i]--; if (MIN <= i-DI && i-DI <= MAX) item[i-DI] = 1+m; } // last else item = null; } else { m = item[i1]; if (n-K+1 > m) { item[i1] = 1; i = i1; while (MIN <= i && i <= MAX && 1 === item[i]) i-=DI; item[i]--; if (MIN <= i+DI && i+DI <= MAX) item[i+DI] = 1+m; } // last else item = null; } } } else { if (COLEX & order) { item = null; } else if (M && W) { if (M === W) return null; // there is only one, if any return null; } else if (W) { return null; } else if (M) { rem = 0; i = i1; k = item[INFO][LEN]; l = 0; while (MIN <= i && i <= MAX && 1 === item[i]) { if (M === item[i]) l++; i -= DI; rem++; k--; } if (i < MIN || i > MAX) { item = null; } else { if (1 === item[INFO][NMAX] && M === item[i]) { if (n === M) { item = null; } else if (M <= rem+1) { if (M === item[i]) item[INFO][NMAX]--; item[i]--; rem++; item[INFO][LEN] = k; item[INFO][NMAX]-=l; while (0 < rem) { i += DI; item[i] = stdMath.min(M, rem); item[INFO][LEN]++; if (M === item[i]) item[INFO][NMAX]++; rem -= item[i]; } } else if (M < item[i]+rem) { if (M === item[i]) item[INFO][NMAX]--; item[i]-=M-rem; rem=M; item[INFO][LEN] = k; item[INFO][NMAX]-=l; while (0 < rem) { i += DI; item[i] = stdMath.min(M, rem); item[INFO][LEN]++; if (M === item[i]) item[INFO][NMAX]++; rem -= item[i]; } } else { if (M === item[i]) l++; rem+=item[i]; i-=DI; k--; while (MIN <= i && i <= MAX && 1 === item[i]) { if (M === item[i]) l++; i-=DI; rem++; k--; } /*if (0 > DI) { MIN = LN-(item[INFO][LEN]||1); MAX = LN-1; } else { MIN = 0; MAX = item[INFO][LEN]-1; }*/ if (i < MIN || i > MAX) { item = null; } else { if (M === item[i]) item[INFO][NMAX]--; item[i]--; rem++; item[INFO][LEN] = k; item[INFO][NMAX]-=l; while (0 < rem) { i += DI; item[i] = stdMath.min(M, rem); item[INFO][LEN]++; if (M === item[i]) item[INFO][NMAX]++; rem -= item[i]; } } } } else { if (M === item[i]) item[INFO][NMAX]--; item[i]--; rem++; item[INFO][LEN] = k; item[INFO][NMAX]-=l; while (0 < rem) { i += DI; item[i] = stdMath.min(M, rem); item[INFO][LEN]++; if (M === item[i]) item[INFO][NMAX]++; rem -= item[i]; } } } } else { if (n > item[INFO][LEN]) { i = i1; rem = 0; while (MIN <= i && i <= MAX && 1 === item[i]) {i-=DI; rem++;} m = item[i]-1; item[i] = m; rem++; if (0 < rem) { if (MIN <= i+DI && i+DI <= MAX) { i+=DI; item[i]=rem; rem=0; item[INFO][LEN] = 0 > DI ? LN-i : i+1; } else { while (0 < rem--) {i+=DI; item[i] = 1; item[INFO][LEN]++;} } } } // last else item = null; } } } else { // compute next composition if (K) { if (COLEX & order) { item = null; } else if (M && W) { if (M === W) return null; // there is only one, if any j = i1; k = 1; i = j-DI; d = M-item[j]; rem = item[j]; while (MIN <= i && i <= MAX && (M < item[i]+1 || W === item[j])) {rem+=item[i]; k++; j = i; i-=DI;} if (MIN > i || i > MAX) { item = null; } else { if (0 < d) { m = rem-1-W*(k-1); if (1 === item[INFO][NMIN] && W === item[i] && k <= m) { item[i] = item[i1]; item[i1] = W; rem -= item[i]-W; } else if (1 === item[INFO][NMAX] && M === item[j] && M > item[i]+1 && M > m) { item[j] = item[i]; item[i] = M; rem -= M-item[j]; } else { if (W === item[i]) item[INFO][NMIN]--; item[i]++; rem--; if (M === item[i]) item[INFO][NMAX]++; } i = i1; m = rem-W*k; while (MIN<=i && i<=MAX && 0 item[i]+1) { item[j] = item[i]; item[i] = M; } else { if (M === item[j]) item[INFO][NMAX]--; if (W === item[i]) item[INFO][NMIN]--; item[i]++; item[j]--; if (W === item[j]) item[INFO][NMIN]++; if (M === item[i]) item[INFO][NMAX]++; } } } } else if (W) { if (n-W*(K-1) > item[i0]) { i = i1; while (MIN <= i && i <= MAX && W === item[i]) i-=DI; j = i-DI; if (1 === item[INFO][NMIN] && W === item[j]) { item[j] = item[i]; item[i] = W; } else { if (W === item[j]) item[INFO][NMIN]--; item[i]--; item[j]++; if (W === item[i]) item[INFO][NMIN]++; m = item[i]; item[i] = item[i1]; item[i1] = m; } } // last else item = null; } else if (M) { j = i1; k = 1; i = j-DI; d = M-item[j]; rem = item[j]; while (MIN <= i && i <= MAX && ((M && M < item[i]+1) || 1 === item[j])) {rem+=item[i]; k++; j = i; i-=DI;} if (MIN > i || i > MAX) { item = null; } else { if (0 < d) { if (M && 1 === item[INFO][NMAX] && M === item[j] && M > item[i]+1 && M > rem-(k-1)-1) { item[j] = item[i]; item[i] = M; rem-=M-item[j]; } else { item[i]++; rem--; if (M === item[i]) item[INFO][NMAX]++; } l = 0; i = i1; while (MIN<=i && i<=MAX && 0 item[i]+1) { item[j] = item[i]; item[i] = M; } else { if (M === item[j]) item[INFO][NMAX]--; item[i]++; item[j]--; if (M === item[i]) item[INFO][NMAX]++; } } } } else { // adapted from FXT lib if (COLEX & order) { if (n-K+1 > item[i1]) { i = i0; while (MIN <= i && i <= MAX && 1 === item[i]) i+=DI; m = item[i]; item[i] = 1; item[i0] = m-1; if (MIN <= i+DI && i+DI <= MAX) item[i+DI]++; } // last else item = null; } else { if (n-K+1 > item[i0]) { i = i1; while (MIN <= i && i <= MAX && 1 === item[i]) i-=DI; m = item[i]; item[i] = 1; item[i1] = m-1; if (MIN <= i-DI && i-DI <= MAX) item[i-DI]++; } // last else item = null; } } } else { if (COLEX & order) { item = null; } else if (M) { if (M === W) return null; // there is only one, if any w = W ? W : 1; i = i1; rem = item[i]; if (M === item[i]) item[INFO][NMAX]--; if (W && W === item[i]) item[INFO][NMIN]--; item[INFO][LEN]--; i -= DI; while (null != W && MIN<=i && i<=MAX && rem<1+W) { rem += item[i]; item[INFO][LEN]--; if (M === item[i]) item[INFO][NMAX]--; if (W === item[i]) item[INFO][NMIN]--; i -= DI; } if (MIN > i || MAX < i) { return null; } k = item[INFO][LEN]; if (0 === item[INFO][NMAX]) { if (n === M) { return null; } else { j = i; rem -= M-item[i]; item[i] = M; item[INFO][NMAX]++; while (w <= rem) { i += DI; item[i] = w; rem -= w; item[INFO][LEN]++; if (W) item[INFO][NMIN]++; if (M === item[i]) item[INFO][NMAX]++; } if (null != W && 0 === item[INFO][NMIN]) { rem += item[i]-W; item[i] = W; item[INFO][NMIN]++; } } } else { l = 0; r = 0; m = 0; while (MIN <= i && i <= MAX && (M === item[i])) { l++; m += item[i]; i -= DI; k--; } /*if (0 > DI) { MIN = LN-(item[INFO][LEN]||1); MAX = LN-1; } else { MIN = 0; MAX = item[INFO][LEN]-1; }*/ if (MIN > i || MAX < i) { return null; } else { j = i; item[i]++; rem += m-1; item[INFO][LEN] = k; item[INFO][NMAX] -= l; if (M === item[i]) item[INFO][NMAX]++; if (0 === item[INFO][NMAX]) { m = M; rem -= m; } else { m = 0; } while (w <= rem) { i += DI; item[i] = w; rem -= w; item[INFO][LEN]++; if (W) item[INFO][NMIN]++; if (M === item[i]) item[INFO][NMAX]++; } if (W && 0 === item[INFO][NMIN]) { rem += item[i]-W; item[i] = W; item[INFO][NMIN]++; } if (0 < m) { i += DI; item[i] = M; item[INFO][LEN]++; item[INFO][NMAX]++; } } if (0 < rem) { /*if (0 > DI) { MIN = LN-(item[INFO][LEN]||1); MAX = LN-1; } else { MIN = 0; MAX = item[INFO][LEN]-1; }*/ while(MIN<=i && i<=MAX && /*0<=DI*(i-j) &&*/ 0 m) { if (W && W === m) { if (1 === item[INFO][NMIN]) { item[i] = item[i+DI]; item[i+DI] = m; } else { item[INFO][NMIN]--; item[i] = stdMath.min(M, m+rem); rem -= item[i]-m; if (M === item[i]) item[INFO][NMAX]++; } } else { item[i] = stdMath.min(M, m+rem); rem -= item[i]-m; if (M === item[i]) item[INFO][NMAX]++; } } i -= DI; } if (0 < rem) { return null; } } } } else { if (W) { w = W; m = n-W; } else { w = 1; m = n; } if (m > item[i0]) { i = i1; rem = item[i]; item[INFO][LEN]--; if (W && W === item[i]) item[INFO][NMIN]--; i -= DI; if (W && W === item[i]) item[INFO][NMIN]--; item[i]++; rem--; while (w <= rem) { i += DI; item[i] = w; rem -= w; item[INFO][LEN]++; if (W) item[INFO][NMIN]++; } if (W && 0 === item[INFO][NMIN]) { rem += item[i]-W; item[i] = W; item[INFO][NMIN]++; } if (0 < rem) { if (W && 1 === item[INFO][NMIN] && W === item[i]) { if (W < rem) { rem += item[i]; item[INFO][LEN]--; item[INFO][NMIN]--; i -= DI; item[i]++; rem--; while (w <= rem) { i += DI; item[i] = w; rem -= w; item[INFO][LEN]++; item[INFO][NMIN]++; } if (0 < rem) { if (W === item[i]) item[INFO][NMIN]--; item[i] += rem; } } else { item[i-DI] += rem; } } else { if (W && W === item[i]) item[INFO][NMIN]--; item[i] += rem; } rem = 0; } if (0 < rem) item = null; } // last else item = null; } } } return item; } // https://en.wikipedia.org/wiki/Partition_of_a_set // https://en.wikipedia.org/wiki/Bell_number SetPartition = Abacus.SetPartition = Class(CombinatorialIterator, { // extends and implements CombinatorialIterator constructor: function SetPartition(n, $) { var self = this, sub = null, K; if (!is_instance(self, SetPartition)) return new SetPartition(n, $); $ = $ || {}; $.type = "partition"; n = n||0; if (is_instance(n, CombinatorialIterator)) { sub = n; n = sub.base(); } else { sub = $.sub; } K = null != $["parts="] ? $["parts="]|0 : null; $.base = n; $.mindimension = stdMath.max(0, null != K ? K : 1); $.maxdimension = stdMath.max(0, null != K ? K : n); $.dimension = $.maxdimension; $.rand = $.rand || {}; $.rand["partition"] = 1; CombinatorialIterator.call(self, "SetPartition", n, $, sub?{method:$.submethod,iter:sub,pos:$.subpos,cascade:$.subcascade}:null); } ,__static__: { C: CombinatorialIterator.C ,P: CombinatorialIterator.P ,T: CombinatorialIterator.T ,DUAL: function(item, n, $, dir) { return item; } ,count: function(n, $) { var K = $ && null!=$["parts="] ? $["parts="]|0 : null; return 0= K || K > n ? Abacus.Arithmetic.O : stirling(n, K, 2))) : Abacus.Arithmetic.O; } ,initial: function(n, $, dir) { var klass = this, item, order = $ && null!=$.order ? $.order : LEX, K = $ && null!=$["parts="] ? $["parts="]|0 : null; if ((0 > n) || (null != K && (0 >= K || K > n))) return null; dir = -1 === dir ? -1 : 1; if ((REVERSED&order)) dir = -dir; // O(n) /* item = new Array(n+1); item[n] = [n, new Array(n)]; if (K) { // restricted setpartition to exactly K parts item[n].push(array(K, 0)); item = operate(function(item,ai,i){ if (0 > dir) { ai = i <= n-K ? 0 : K-n+i; item[i] = ai; item[n][1][i] = ai; item[n][2][ai]++; } else { ai = i < K ? i : K-1; item[i] = ai; item[n][1][i] = ai; item[n][2][ai]++; } return item; }, item, null, 0, n-1, 1); } else { // unrestricted setpartition item = operate(function(item,ai,i){ if (0 > dir) { item[i] = 0; item[n][1][i] = 0; } else { item[i] = i; item[n][1][i] = i; } return item; }, item, null, 0, n-1, 1); } */ if (0 > dir) { item = K ? array(K, function(i){return 0 === i ? array(n-K+1, 0, 1) : [n-K+i];}) : [array(n, function(i){return i;})]; } else { item = K ? array(K, function(i){return i+1 === K ? array(n-K+1, K-1, 1) : [i];}) : array(n, function(i){return [i];}); } return item; } ,valid: function(item, n, $) { var klass = this, K = $ && null!=$["parts="] ? $["parts="]|0 : null, l, k, i, j, s, x, m, dict, d0, d1; if (!item || 0>n) return false; d0 = stdMath.max(0, null != K ? K : 1); d1 = stdMath.max(0, null != K ? K : n); if (d0 > item.length || d1 < item.length) return false; item = klass.DUAL(item.slice(), n, $); for (dict={},m=0,j=0,k=item.length; j x || x >= n || 1 === dict[x] || (i+1= s[i+1])) return false; dict[x] = 1; } m += l; } return m === n; } ,succ: function(item, index, n, $, dir) { if ((null == n) || (null == item) || (0 >= n)) return null; dir = -1 === dir ? -1 : 1; return next_setpartition(item, n, $ && null!=$["parts="] ? $["parts="]|0 : null, dir, $ && null!=$.order ? $.order : LEX); } ,rand: function(n, $) { var klass = this, K = $ && null!=$["parts="] ? $["parts="]|0 : null, rnd = Abacus.Math.rnd, Arithmetic = Abacus.Arithmetic, q, m, l, i, k, prob, cdf; if ((0 > n) || (null != K && (0 >= K || K > n))) return null; q = array(n, 0); m = n; l = 0; while (0 < m) { cdf = Rational.Zero(); prob = Rational.fromDec(rnd()); k = 1; while (k <= m) { cdf = cdf.add(Rational(Arithmetic.mul(factorial(m-1,k-1), klass.count(m-k, {"parts=":K})), klass.count(m, {"parts=":K}))); if (cdf.gte(prob)) break; k++; } for (i=m-k; i=K) l = 0; m -= k; } q = shuffle(q); return operate(function(partition, i){ partition[q[i]].push(i); return partition; }, array(stdMath.max.apply(null, q)+1, function(){return [];}), null, 0, n-1, 1).sort(function(a,b){return a[0]-b[0];}); } // random unranking, another method for unbiased random sampling ,randu: CombinatorialIterator.rand ,rank: NotImplemented ,unrank: NotImplemented ,toConjugate: conjugatesetpartition } ,_update: function() { var self = this, n = self.n, $ = self.$, K = null!=$["parts="] ? $["parts="]|0 : null, item = self.__item, i, j, s, k; if (item && (n+1 !== item.length)) { self.__item = new Array(n+1); self.__item[n] = [n, new Array(n)]; if (K) self.__item[n].push(array(K, 0)); for (i=0; in ? Abacus.Arithmetic.O : catalan(n); } ,initial: function(n, $, dir) { var klass = this, item, j, order = $ && null!=$.order ? $.order : LEX; if ((0 > n)) return null; dir = -1 === dir ? -1 : 1; if ((REVERSED&order)) dir = -dir; // O(n) item = array(n, function(i){return 0 > dir ? 2*i : i;}); j = 0; return array(2*n, function(i){ if (jn) return false; if (n === item.length) { j = 0; item = array(2*n, function(i){ if (j= stack) return false; stack--; } else return false; } return 0 === stack; } ,succ: function(item, index, n, $, dir) { if ((null == n) || (null == item) || (0 >= n)) return null; dir = -1 === dir ? -1 : 1; return next_catalan(item, n, dir, $ && null!=$.order ? $.order : LEX); } ,rand: function(n, $) { var klass = this, seq, prefix, suffix, word, partial_sum, i, s, nn; if (0 > n) return null; // "Generating binary trees at random", Atkinson & Sack, 1992 // adapted from https://gist.github.com/rygorous/d57941fa5ae6beb59f17bc30793d3d75 nn = 2*n; seq = shuffle(array(nn, function(i){return i < n ? 1 : -1;})); prefix = []; suffix = []; word = []; partial_sum = 0; for (i=0; i dir) { if (COLEX & order) { j = 0; while (jj; --i,--j) item[j] = i; for (; 0=j) { item = null; break; } else { item[j] = z - 1; break; } } m -= 2; item[j] = m; z = y; --j; y = 0 j) { item = null; } else { t = item[j]; i = j; do { item[i++] = ++t; } while (i= n) return null; // try to construct a (pan-)diagonal latin square first diag = 0; if ((n&1) /* odd */ && (n%3) /* not divisable by 3 */) { a = 2; b = 1; diag = 2; // conditions met for (pan-)diagonal square } else if (n&1 /* odd */) { // else try an exhaustive search over the possible factors Nn = N(n); for (i=1; i= n || 2 === n) return null; // trivial if (1 === n) return [[1]]; var i, j, k, odd = n&1, even = 1-odd, doubly_even = 0 === (/*n%4*/n&3), nn = n*n, n2 = (n-odd)>>>1, O, o, n22, a, b, c, lc, rc, t, n12, n21, magic; magic = new Array(n); for (i=0; i= n) { i++; j=0; } magic[i][j] = ((n12+j-i)%n)*n + ((n21+i+j)%n)+1; } } else if (doubly_even) // doubly-even order { // O(n^2) for (k=0,i=0,j=0; k= n) { i++; j=0; } magic[i][j] = (((i+1)/*%4*/&3)>>>1 === ((j+1)/*%4*/&3)>>>1) ? nn-k : k+1; } } else //if (even) // singly-even order { // O((n/2)^2) O = magic_square(n2); n22 = n2*n2; a = n22; b = a<<1; c = b+n22; for (k=0,i=0,j=0; k= n2) { i++; j=0; } o = O[i][j]; magic[i][j] = o; magic[i+n2][j+n2] = o + a; magic[i+n2][j] = o + b; magic[i][j+n2] = o + c; } lc = n2>>>1; rc = lc; for (j=0; j n - rc) || (i === lc && j === lc)) && !(i === 0 && j === lc)) { t = magic[i][j]; magic[i][j] = magic[i][j + n2]; magic[i][j + n2] = t; } } } } return magic; } ,product: function(/* args */) { if (1 >= arguments.length) return arguments[0]; var m = arguments, nm = m.length, m1, m2, mm = m[0], mult, n1, n2, n22, n12, k=1, i, j, i1, i2, j1, j2; while (k < nm) { m1 = mm; m2 = m[k++]; n1 = m1.length; n2 = m2.length; n22 = n2*n2; n12 = n1*n2; mm = new Array(n12); for (i=0; i= n2) { i2++; j2=0; if (i2 >= n2) { j1++; j+=n2; i2=0; j2=0; if (j1 >= n1) { i1++; i+=n2; j1=0; j=0; i2=0; j2=0; } if (i1 < n1 && j1 < n1) mult = (m1[i1][j1]-1)*n22; } } } } return mm; } ,pythagorean: NotImplemented ,toString: function(s) { var n, len, out = '', i; if (null == s) return out; n = s.length; len = String(n*n).length; for (i=0; i