///
///
///
///
module ToomCook {
class ExecutorStatus {
abort: boolean;
constructor() {
this.abort = false;
}
cancel(): void {
this.abort = true;
}
isCancel(): boolean {
return this.abort;
}
}
var logger = (message: string) => { console.log(new Date() + ' : ' + message); };
var blankprmfn = (param?) => new Promise((resolve) => { resolve(param) });
var noopwait_lastexec = Date.now(), noopwait_th = 150;
var noopwaitfn = (param?) => {
var now = Date.now();
return new Promise(
(now < noopwait_lastexec || noopwait_lastexec + noopwait_th < now) ?
(resolve) => { setTimeout(() => { noopwait_lastexec = Date.now(); resolve(param) }, 0) } :
(resolve) => { resolve(param) }
);
};
var noopwaitwithcancel = (execstat?: ExecutorStatus) => (param?) => noopwaitfn(param).then(
(param?) => (execstat && execstat.isCancel()) ? Promise.reject(new Error("Execution Canceled")) : param
);
var getElementById = (elementId: string) => document.getElementById(elementId),
createDocumentFragment = (children?: Node[]) => { var f = document.createDocumentFragment(); if (children) { children.forEach((e) => { f.appendChild(e) }) } return f; },
createTextNode = (data: string) => document.createTextNode(data),
setAttribute = (element: T, attName:string, className: string): T => { element.setAttribute(attName, className); return element; },
setElementValue = (element: T, value: string): T=> setAttribute(element, 'value', value),
appendTextNode = (node: T, text: string): T => { node.appendChild(createTextNode(text)); return node; },
appendChild = (node: T, child: Node): T => { node.appendChild(child); return node; },
appendChildren = (node: T, children: Node[]): T => { children.forEach((e) => { node.appendChild(e) }); return node; },
createElement = (tagName: string, className?: string) => { var element = document.createElement(tagName); if (className) { element.setAttribute('class', className); } return element; },
createDivElement = () => createElement('div'),
createParagraphElement = () => createElement('p'),
createProgressElement = () => createElement('progress'),
createSelectElement = () => document.createElement('select'),
createButton = (text: string) => appendTextNode(createElement('button'), text),
createSquareBracket = (child: Node) => appendChild(createElement('span', 'SquareBracket'), child),
createMathEq = (left: Node[], right: Node[]) => appendChildren(appendTextNode(appendChildren(createElement('span', 'MathSpan'), left), ' = '), right),
createMathCal = (text: string) => appendTextNode(createElement('span', 'MathCal'), text),
createMathIt = (text: string) => appendTextNode(createElement('span', 'MathIt'), text),
createSubElement = (text: string) => appendTextNode(createElement('sub'), text),
createTr = (children: Node[]) => appendChildren(createElement('tr'), children),
createTbody = (children: Node[]) => appendChildren(createElement('tbody'), children),
createFracNum = (text: string) => appendTextNode(createElement('td', 'FracNum'), text),
createFracDenom = (text: string) => appendTextNode(createElement('td', 'FracDenom'), text),
createFracTbl = (child: Node) => appendChild(createElement('table', 'FracTbl'), child),
createMatrixTbl = (child: Node) => appendChild(createElement('table', 'MatrixTbl'), child),
createMatrixElement = (child: Node) => appendChild(createElement('td', 'MatrixElement'), child),
createOption = (value: string, text: string) => appendTextNode(setElementValue(createElement('option'), value), text),
replaceChildDom = (parent: Node, newChild: Node) => {
while (parent.firstChild) {
parent.removeChild(parent.firstChild);
}
parent.appendChild(newChild);
},
hideChildElement = (parent: HTMLElement) => {
[].forEach.call(parent.children, (child: HTMLElement) => {
var classVal = child.getAttribute('class');
child.setAttribute('class', classVal? 'transHide ' + classVal: 'transHide');
});
};
var clip_fn = (parent: Node) => (s: string) => {
((btn: HTMLElement) => {
btn.setAttribute('class', 'copytxtbtn');
btn.setAttribute('data-clipboard-text', s);
replaceChildDom(parent, btn);
btn.addEventListener('mouseleave', () => {
btn.setAttribute('class', 'copytxtbtn');
btn.removeAttribute('aria-label');
});
((clip) => {
clip.on('success', (e) => {
e.trigger.setAttribute('class', 'copytxtbtn tooltipped tooltipped-e');
e.trigger.setAttribute('aria-label', 'Copied!');
e.clearSelection();
});
clip.on('error', (e) => {
e.trigger.setAttribute('class', 'copytxtbtn tooltipped tooltipped-e');
e.trigger.setAttribute('aria-label', 'Copy failed...');
e.clearSelection();
});
})(new Clipboard(btn));
})(createButton('Copy to clipboard'));
};
interface matBuilder { (i: number, j: number): T }
interface matCallback { (m: Matrix): void }
interface plainFunc { (): void }
interface progressCallback { (value: number): void }
interface prebuilddata {
n: number;
toom: number;
base: Array>;
inv: Array>;
}
interface basicAcc {
zero: T;
one: T;
add(a: T, b: T): T;
subtract(a: T, b: T): T;
negate(a: T): T;
multiply(a: T, b: T): T;
divide(a: T, b: T): T;
isZero(a: T): boolean;
String(a: T): string;
Html(a: T): Node;
}
interface OneBase {
0: number;
1: number;
}
interface BaseSet {
name: string;
base: OneBase[];
pmat: Matrix;
imat: Matrix;
}
var baseAry: BaseSet[] = [];
class iRat {
num: BigInteger;
denom: BigInteger;
constructor(num: BigInteger, denom: BigInteger) {
this.num = num;
this.denom = denom;
}
}
var iRatReduce = (rat: BigRational, denomlcm: BigInteger): iRat =>
rat.denom.isUnit() ? new iRat(rat.num, rat.denom) : new iRat(rat.num.multiply(denomlcm.divide(rat.denom)), denomlcm);
var RatHtml = (num: BigInteger, denom: BigInteger): Node => denom.isUnit() ?
createTextNode(num.toString()) :
createFracTbl(createTbody([
createTr([createFracNum(num.toString())]),
createTr([createFracDenom(denom.toString())])
]));
var NumberAcc: basicAcc = {
zero: 0,
one: 1,
add: (a, b) => a + b,
subtract: (a, b) => a - b,
negate: (a) => -a,
multiply: (a, b) => a * b,
divide: (a, b) => a / b,
isZero: (a) => a == 0,
String: (a) => '' + a,
Html: (a) => createTextNode('' + a)
};
var bigIntAcc: basicAcc = {
zero: bigInt.zero,
one: bigInt.one,
add: (a, b) => a.add(b),
subtract: (a, b) => a.subtract(b),
negate: (a) => a.negate(),
multiply: (a, b) => a.multiply(b),
divide: (a, b) => a.divide(b),
isZero: (a) => a.isZero(),
String: (a) => a.toString(),
Html: (a) => createTextNode(a.toString())
};
var bigRatAcc: basicAcc = {
zero: bigRat.zero,
one: bigRat.one,
add: (a, b) => a.add(b),
subtract: (a, b) => a.subtract(b),
negate: (a) => a.negate(),
multiply: (a, b) => a.multiply(b),
divide: (a, b) => a.divide(b),
isZero: (a) => a.isZero(),
String: (a) => a.denom.isUnit() ? a.num.toString() : a.toString(),
Html: (a) => RatHtml(a.num, a.denom)
};
var iRatAcc: basicAcc = {
zero: new iRat(bigInt.zero, bigInt.one),
one: new iRat(bigInt.one, bigInt.one),
add: null,
subtract: null,
negate: null,
multiply: null,
divide: null,
isZero: (a) => a.num.isZero(),
String: (a) => a.denom.isUnit() ? a.num.toString() : (a.num.toString() + "/" + a.denom.toString()),
Html: (a) => RatHtml(a.num, a.denom)
};
var StringAcc: basicAcc = {
zero: "0",
one: "1",
add: null,
subtract: null,
negate: null,
multiply: null,
divide: null,
isZero: (a) => +a === 0,
String: (a) => a,
Html: (a) => createTextNode(a)
};
var HtmlAcc: basicAcc = {
zero: null,
one: null,
add: null,
subtract: null,
negate: null,
multiply: null,
divide: null,
isZero: null,
String: null,
Html: (a) => a
};
class Matrix {
x: number;
y: number;
m: T[][];
acc: basicAcc;
constructor(x: number, y: number, acc: basicAcc) {
this.x = x | 0;
this.y = y | 0;
this.m = new Array(y);
this.acc = acc;
for (var j = 0; j < y; ++j) {
this.m[j] = new Array(x);
}
}
static build(e: matBuilder, x: number, y: number, acc: basicAcc): Matrix {
x |= 0;
y |= 0;
var r = new Matrix(x, y, acc), m = r.m, i, j;
for (i = 0; i < y; ++i) {
for (j = 0; j < x; ++j) {
m[i][j] = e(i, j);
}
}
return r;
}
static buildPromise(e: matBuilder, x: number, y: number, acc: basicAcc, execstat: ExecutorStatus = new ExecutorStatus(), progress?: progressCallback): Promise> {
x |= 0;
y |= 0;
var r = new Matrix(x, y, acc), m = r.m, i: number, j: number, prm: Promise, prcnt = 0, prdiv = x * y;
prm = blankprmfn();
for (i = 0; i < y; ++i) {
for (j = 0; j < x; ++j) {
((i, j) => {
if (progress) { progress(prcnt++ / prdiv); }
prm = prm.then(noopwaitwithcancel(execstat)).then(
() => { m[i][j] = e(i, j); }
);
})(i, j);
}
}
return prm.then(() => r);
}
multiply(b: Matrix): Matrix {
var am: T[][] = this.m, bm: T[][] = b.m, acc = this.acc;
if (this.x !== b.y) { throw "matrix size mismatch" }
return Matrix.build(
(i, j) => am[i].map((v, k) => acc.multiply(v, bm[k][j])).reduce((p, c) => acc.add(p, c)),
b.x, this.y, acc
);
}
multiplyPromise(b: Matrix, execstat: ExecutorStatus = new ExecutorStatus(), progress?: progressCallback): Promise> {
var am: T[][] = this.m, bm: T[][] = b.m, acc = this.acc;
return (this.x !== b.y) ?
Promise.reject(new Error("matrix size mismatch")) :
Matrix.buildPromise(
(i, j) => am[i].map((v, k) => acc.multiply(v, bm[k][j])).reduce((p, c) => acc.add(p, c)),
b.x, this.y, acc, execstat, progress
);
}
LUPinversePromise(execstat: ExecutorStatus = new ExecutorStatus(), progress: progressCallback = () => { }): Promise> {
// ref: https://msdn.microsoft.com/ja-jp/magazine/jj863137.aspx
var $t = this, acc: basicAcc, n: number, lu: Matrix, lum: T[][], inv: Matrix, invm: T[][], p: number[], i: number, j: number, k: number, execstat: ExecutorStatus, prm: Promise, checkpoint: () => any;
var progress_cnt_lup: number, progress_con_lup: number, progress_cnt_slv: number, progress_con_slv: number;
prm = new Promise((resolve, reject) => {
if ($t.x !== $t.y) {
reject(new Error("non square matrix"));
} else {
acc = $t.acc;
n = $t.x;
lu = Matrix.build((i, j) => $t.m[i][j], n, n, acc);
lum = lu.m;
p = $t.m.map((e, t) => t);
inv = new Matrix(n, n, acc);
invm = inv.m;
progress_cnt_lup = progress_cnt_slv = 0;
progress_con_lup = 3.0 / (n * (n - 1) * (2 * n - 1));
progress_con_slv = 0.5 / (n * (n - 1));
resolve();
}
});
checkpoint = (param?) => noopwaitfn(param).then(
(param?) => execstat.isCancel() ?
Promise.reject(new Error("LUPinverse execution canceled")) : param
);
// Doolittle LUP decomposition
for (j = 0; j < n - 1; ++j) {
prm = (
(prm, j) => prm.then(
() => {
var rowPtr: T[], tmp: number;
if (acc.isZero(lum[j][j])) {
for (i = j + 1; i < n; ++i) {
if (!acc.isZero(lum[i][j])) {
rowPtr = lum[i]; lum[i] = lum[j]; lum[j] = rowPtr;
tmp = p[i]; p[i] = p[j]; p[j] = tmp;
break;
}
}
if (i >= n) {
return Promise.reject(new Error("non inversible matrix"));
}
}
}
).then(
() => {
var prm_in: Promise = blankprmfn();
for (i = j + 1; i < n; ++i) {
prm_in = prm_in.then(() => {
progress(progress_cnt_lup * progress_con_lup);
progress_cnt_lup += n - j - 1;
}).then(checkpoint).then(
(
(i, j) => () => {
if (!acc.isZero(lum[i][j])) {
lum[i][j] = acc.divide(lum[i][j], lum[j][j]);
for (k = j + 1; k < n; ++k) {
if (!acc.isZero(lum[j][k])) {
lum[i][k] = acc.subtract(lum[i][k], acc.multiply(lum[i][j], lum[j][k]));
}
}
}
}
)(i, j)
);
}
return prm_in;
}
)
)(prm, j);
}
// Solve Inverse
for (k = 0; k < n; ++k) {
prm = ((prm, k) => {
var b: T[] = new Array(n);
for (var i = 0; i < n; ++i) {
b[i] = (k == p[i] ? acc.one : acc.zero);
}
return prm.then(() => {
var prm_in: Promise = blankprmfn();
for (i = 1; i < n; ++i) {
prm_in = prm_in.then(
() => {
progress(.5 + progress_cnt_slv * progress_con_slv);
progress_cnt_slv += 1;
}
).then(checkpoint).then(
(
(i, k) => () => {
for (j = 0; j < i; ++j) {
if (!acc.isZero(lum[i][j]) && !acc.isZero(b[j])) {
b[i] = acc.subtract(b[i], acc.multiply(lum[i][j], b[j]));
}
}
}
)(i, k)
);
}
for (i = n - 2; i >= 0; --i) {
prm_in = prm_in.then(checkpoint).then(((i, k) => () => {
for (j = i + 1; j < n; ++j) {
if (!acc.isZero(lum[i][j]) && !acc.isZero(b[j])) {
b[i] = acc.subtract(b[i], acc.multiply(lum[i][j], b[j]));
}
}
b[i] = acc.divide(b[i], lum[i][i]);
})(i, k));
}
prm_in = prm_in.then(() => {
for (j = 0; j < n; ++j) {
invm[j][k] = b[j];
}
});
return prm_in;
});
})(prm, k);
}
return prm.then>(() => inv);
}
toString(): string {
return (
(accString: (T) => string) => "[" + this.m.map(
(f) => "[" + f.map(
(e) => accString(e)
).join(",") + "]"
).join(",") + "]"
)(this.acc.String);
}
toStringPromise(execstat?: ExecutorStatus): Promise {
return (
(accString: (T) => string) => Promise.all(this.m.map(
(v) => Promise.all(v.map(
(e) => noopwaitwithcancel(execstat)().then(() => accString(e))
)).then((cols) => cols.join(','))
)).then((rows) => rows.join(','))
)(this.acc.String);
}
toHtml(): HTMLElement {
return (
(accHtml: (T) => Node) => createMatrixTbl(createTbody(this.m.map(
(e) => createTr(e.map(
(f) => createMatrixElement(accHtml(f))
))
)))
)(this.acc.Html);
}
toHtmlPromise(execstat?: ExecutorStatus): Promise {
return (
(accHtml: (T) => Node) => Promise.all(this.m.map(
(v) => Promise.all(v.map(
(e) => noopwaitwithcancel(execstat)().then(() => createMatrixElement(accHtml(e)))
)).then((cols) => createTr(cols))
)).then((rows) => createSquareBracket(createMatrixTbl(createTbody(rows))))
)(this.acc.Html);
}
}
var matrixBuildInt = (e: matBuilder, x: number, y: number) => Matrix.build(e, x, y, bigIntAcc);
var matrixBuildRat = (e: matBuilder, x: number, y: number) => Matrix.build(e, x, y, bigRatAcc);
var matrixHtml = (e: matBuilder, x: number, y: number): Node => Matrix.build(e, x, y, HtmlAcc).toHtml();
var matrixBuildIntPromise = (e: matBuilder, x: number, y: number, execstat?: ExecutorStatus) => Matrix.buildPromise(e, x, y, bigIntAcc, execstat);
var matrixBuildIRatPromise = (e: matBuilder, x: number, y: number, execstat?: ExecutorStatus) => Matrix.buildPromise(e, x, y, iRatAcc, execstat);
var genBaseA = (t: number): OneBase[] => {
var l: number, x: OneBase[], i: number, b: number;
l = t * 2 - 2 | 0;
x = [[0, 1], [-1, 1], [1, 1]];
for (i = 0; x.length < l; ++i) {
b = 2 << i;
x = x.concat([[-b, 1], [b, 1], [-1, b], [1, b]]);
}
return x.slice(0, l).concat([[1, 0]]).reverse();
};
var genBaseB = (t: number): OneBase[] => {
var l: number, x: OneBase[], i: number, j: number;
l = t * 2 - 2 | 0;
x = [[0, 1], [-1, 1], [1, 1]];
for (i = 2; x.length < l; ++i) {
for (j = 1; j < i && x.length < l; ++j) {
if (bigInt.gcd(bigInt(i), bigInt(j)).isUnit()) {
x = x.concat([[-i, j], [i, j], [-j, i], [j, i]]);
}
}
}
return x.slice(0, l).concat([[1, 0]]).reverse();
};
var genBaseC = (t: number): OneBase[] => {
var l: number, x: OneBase[], i: number;
l = t * 2 - 2 | 0;
x = [[0, 1], [-1, 1], [1, 1]];
for (i = 2; x.length < l; i = i + 1 | 0) {
x = x.concat([[-i, 1], [i, 1], [-1, i], [1, i]]);
}
return x.slice(0, l).concat([[1, 0]]).reverse();
};
var toomPmat = (b: OneBase[]) => matrixBuildRat((i, j) => bigRat(bigInt(b[i][0]).pow(b.length - j - 1).times(bigInt(b[i][1]).pow(j))), b.length, b.length);
var toomPmatPreMatPromise = (b: OneBase[], width: number, execstat?: ExecutorStatus) => matrixBuildIntPromise((i, j) => bigInt(b[i][0]).pow(width - j - 1).times(bigInt(b[i][1]).pow(j)), width, b.length, execstat);
var OneBaseStr = (e: OneBase) => e[1] == 0 ? "\u221e" : e[1] == 1 ? e[0] + "" : e[0] + "/" + e[1];
var BaseStr = (m: OneBase[]) => "[" + m.map(OneBaseStr).join(", ") + "]";
var BaseStr_snip = (m: OneBase[]) => (m.length > 10) ? "[" + m.slice(0, 10).map(OneBaseStr).join(", ") + ", ...]" : BaseStr(m);
var toomCalHtml = (calstr: string, c: OneBase): Node => createDocumentFragment([createMathCal(calstr), createTextNode('(' + OneBaseStr(c) + ')')]);
var aryidxHtml = (arystr: string, idx: number): Node => createDocumentFragment([createMathIt(arystr), createSubElement('' + idx)]);
var cHtml = (b: BaseSet): Node =>
createSquareBracket(matrixHtml(
(i, j) => aryidxHtml('C', b.base.length - i - 1), 1, b.base.length
));
var argHtml = (b: BaseSet): Node =>
createSquareBracket(matrixHtml(
(i, j) => [
toomCalHtml('A', b.base[i]), createTextNode(" \u2715 "), toomCalHtml('B', b.base[i])
].reduce(
(f, e) => { f.appendChild(e); return f }, document.createDocumentFragment()
), 1, b.base.length
));
var httpRequest = (method: string, url: string, args?): Promise =>
new Promise((resolve, reject) => {
var client = new XMLHttpRequest();
var uri = url;
if (args && (method === 'POST' || method === 'PUT')) {
uri += '?';
var argcount = 0;
for (var key in args) {
if (args.hasOwnProperty(key)) {
if (argcount++) {
url += '&';
}
uri += encodeURIComponent(key) + '=' + encodeURIComponent(args[key]);
}
}
}
client.open(method, uri);
client.send();
client.onload = () => {
if (client.status >= 200 && client.status < 300) {
resolve(client);
} else {
reject(client.statusText);
}
};
client.onerror = () => {
reject(client.statusText);
};
});
var getRequestJSON = (url): Promise => httpRequest('GET', url).then((xhr) => JSON.parse(xhr.responseText));
var loadMatrix = (b: BaseSet): Promise => {
var url, xhr;
if (
b.name.match(/^base[ABC]_/) && [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 23, 24, 31, 32, 39, 40].some((e) => e == b.base.length) ||
b.name.match(/^base[BC]_/) && [47, 48, 71, 72, 87, 88, 111, 112, 127, 128].some((e) => e == b.base.length)
) {
url = "data/toom_mat_" + (b.base.length < 19 ? "00" : (b.base.length + 1 >> 1)) + ".json";
} else {
return Promise.reject(new Error("not match bases"));
}
return getRequestJSON(url).then(
(resObj) => {
resObj.forEach((e) => {
baseAry.filter((f) =>
e.base.length == f.base.length && e.base.every((g, i) => (g[0] == f.base[i][0] && g[1] == f.base[i][1]))
).forEach((f) => {
f.imat = matrixBuildRat((i, j) => bigRat(e.inv[i][j]), e.n, e.n);
});
});
}
);
};
class ToomMatHtmlContainer_PreMatrixSet {
splitSelectorBlock: HTMLElement;
splitSelector: HTMLSelectElement;
baseSet: BaseSet;
baseText: HTMLElement;
mat_ab: HTMLElement;
splitExecStat: ExecutorStatus;
constructor(target: Node) {
this.splitSelector = createSelectElement();
target.appendChild(createDocumentFragment([
(this.splitSelectorBlock = createParagraphElement()),
(this.baseText = createParagraphElement()),
(this.mat_ab = createDivElement())
]));
}
updateBase(baseSet: BaseSet, execstat: ExecutorStatus): Promise {
var _this = this, execcheck: (any) => Promise = noopwaitwithcancel(execstat);
if (_this.baseSet === baseSet) { return blankprmfn() }
_this.baseSet = baseSet;
return blankprmfn().then(
() => {
if (_this.splitExecStat && _this.splitExecStat !== execstat) {
_this.splitExecStat.cancel();
}
replaceChildDom(_this.baseText, createTextNode("Toom-" + (.5 * baseSet.base.length + .5 | 0) + "." + ((5 * baseSet.base.length + 5) % 10) + " : " + BaseStr(baseSet.base)));
[_this.mat_ab, _this.splitSelectorBlock].forEach(hideChildElement);
}
).then(
() => {
var sel = createSelectElement(), i: number, j: number, m: number, n: number;
j = ((baseSet.base.length + 1) >> 1);
do {
i = baseSet.base.length - j + 1;
sel.appendChild(createOption(i + ',' + j, 'split ' + i + '*' + j));
} while (--j > 1);
_this.splitSelector = sel;
replaceChildDom(_this.splitSelectorBlock, sel);
m = ((baseSet.base.length + 2) >> 1) + sel.selectedIndex;
n = baseSet.base.length - m + 1;
return (sel.onchange = (ev?) => { _this.updateSplit(baseSet, m) })();
}
);
}
updateSplit(baseSet: BaseSet, m: number, execstat: ExecutorStatus = new ExecutorStatus()): Promise {
var _this = this, n = baseSet.base.length - m + 1, f = createDocumentFragment(), execcheck = noopwaitwithcancel(execstat);
if (_this.splitExecStat && _this.splitExecStat !== execstat) {
_this.splitExecStat.cancel();
}
this.splitExecStat = execstat;
hideChildElement(_this.mat_ab);
return ((m == n) ?
toomPmatPreMatPromise(baseSet.base, m, execstat).then((aMat) => aMat.toHtmlPromise(execstat)).then((aMat) => {
var div = createDivElement();
div.appendChild(createMathEq(
[createSquareBracket(matrixHtml((j, i) => toomCalHtml('A', baseSet.base[j]), 1, baseSet.base.length))],
[aMat, createSquareBracket(matrixHtml((j, i) => aryidxHtml(i == 0 ? 'A' : 'B', m - j - 1), 2, m))]
));
f.appendChild(div);
}) :
toomPmatPreMatPromise(baseSet.base, m, execstat).then(
(aMat) => aMat.toHtmlPromise(execstat)
).then(
(aMat) => {
var div = createDivElement();
div.appendChild(createMathEq(
[createSquareBracket(matrixHtml((j, i) => toomCalHtml('A', baseSet.base[j]), 1, baseSet.base.length))],
[aMat, createSquareBracket(matrixHtml((j, i) => aryidxHtml('A', m - j - 1), 1, m))]
));
f.appendChild(div);
}
).then(
() => toomPmatPreMatPromise(baseSet.base, n, execstat)
).then(
(bMat) => bMat.toHtmlPromise(execstat)
).then(
(bMat) => {
var div = createDivElement();
div.appendChild(createMathEq(
[createSquareBracket(matrixHtml((j, i) => toomCalHtml('B', baseSet.base[j]), 1, baseSet.base.length))],
[bMat, createSquareBracket(matrixHtml((j, i) => aryidxHtml('B', n - j - 1), 1, n))]
));
f.appendChild(div);
}
)
).then(execcheck).then(
() => {
replaceChildDom(_this.mat_ab, f);
}
);
}
}
class ToomMatHtmlContainer_PostMatrixSet {
//mat_c: HTMLElement;
baseSet: BaseSet;
mat_invc_1: HTMLElement;
mat_invc_2: HTMLElement;
mat_invc_3: HTMLElement;
btn_invc_1: HTMLElement;
btn_invc_2: HTMLElement;
btn_invc_3: HTMLElement;
status: ExecutorStatus;
constructor(target: Node) {
target.appendChild(createDocumentFragment([
(this.mat_invc_1 = createDivElement()),
(this.btn_invc_1 = createDivElement()),
(this.mat_invc_2 = createDivElement()),
(this.btn_invc_2 = createDivElement()),
(this.mat_invc_3 = createDivElement()),
(this.btn_invc_3 = createDivElement())
//, (this.mat_c = createDivElement())
]));
}
update(baseSet: BaseSet, execstat: ExecutorStatus): Promise {
var _this = this;
return blankprmfn().then(
() => {
if (_this.baseSet !== baseSet) {
_this.baseSet = baseSet;
[/*_this.mat_c,*/ _this.mat_invc_1, _this.mat_invc_2, _this.mat_invc_3, _this.btn_invc_1, _this.btn_invc_2, _this.btn_invc_3].forEach(hideChildElement);
}
}
//).then(() => { replaceChildDom(_this.mat_c, createMathEq([argHtml(baseSet)], [baseSet.pmat.toHtml(), cHtml(baseSet)])); }
).then(baseSet.imat ?
() => {
var a = baseSet.imat, tooma: Matrix, toomb: Matrix, toomc: Matrix, toomb_lcm: BigInteger[], toomc_lcm: BigInteger,
execcheck = noopwaitwithcancel(execstat);
return blankprmfn().then(
() => matrixBuildIRatPromise(
(i, j) => new iRat(a.m[i][j].num, a.m[i][j].denom), a.x, a.y, execstat
).then((m) => { tooma = m; })
).then(execcheck).then(
() => tooma.toHtmlPromise(execstat).then(
(e) => { replaceChildDom(_this.mat_invc_1, createMathEq([cHtml(baseSet)], [e, argHtml(baseSet)])) }
)
).then(
() => tooma.toStringPromise(execstat).then(clip_fn(_this.btn_invc_1))
).then(execcheck).then(
() => {
toomb_lcm = [];
return a.m.reduce(
(p: Promise, c: BigRational[]) => p.then(
() => { toomb_lcm.push(c.reduce((p: BigInteger, c: BigRational) => bigInt.lcm(p, c.denom), bigInt.one)); }
).then(execcheck), blankprmfn()
);
}
).then(
() => matrixBuildIRatPromise(
(i, j) => (
(e: BigRational, l: BigInteger) => e.denom.isUnit() ?
new iRat(e.num, e.denom) :
new iRat(e.num.multiply(l.divide(e.denom)), l)
)(a.m[i][j], toomb_lcm[i]), a.x, a.y, execstat
).then((m) => { toomb = m; })
).then(execcheck).then(
() => toomb.toHtmlPromise(execstat).then(
(e) => replaceChildDom(_this.mat_invc_2, createMathEq([cHtml(baseSet)], [e, argHtml(baseSet)]))
)
).then(
() => toomb.toStringPromise(execstat).then(clip_fn(_this.btn_invc_2))
).then(execcheck).then(
() => {
toomc_lcm = bigInt.one;
return toomb_lcm.reduce(
(p: Promise, c) =>
p.then(
() => { toomc_lcm = bigInt.lcm(toomc_lcm, c); }
), blankprmfn()
);
}
).then(execcheck).then(
() => matrixBuildIntPromise((i, j) => {
var e = a.m[i][j];
return e.num.multiply(toomc_lcm.divide(e.denom));
}, a.x, a.y, execstat).then((m) => { toomc = m; })
).then(execcheck).then(
() => toomc.toHtmlPromise(execstat).then(
(e) => {
replaceChildDom(_this.mat_invc_3, createMathEq([cHtml(baseSet)], [toomc_lcm.isUnit() ? e: createDocumentFragment([RatHtml(bigInt.one, toomc_lcm), e]), argHtml(baseSet)]));
}
)
).then(
() => toomc.toStringPromise(execstat).then(
(s) => toomc_lcm.isUnit() ? s : ("1/" + toomc_lcm.toString() + " * " + s)
).then(clip_fn(_this.btn_invc_3))
);
} : () => {
}
);
}
}
class ToomMatHtmlContainer_BodySet {
preMats: ToomMatHtmlContainer_PreMatrixSet;
postMats: ToomMatHtmlContainer_PostMatrixSet;
constructor(target: Node) {
var fragment = createDocumentFragment();
this.preMats = new ToomMatHtmlContainer_PreMatrixSet(fragment);
this.postMats = new ToomMatHtmlContainer_PostMatrixSet(fragment);
target.appendChild(fragment);
}
update(baseSet: BaseSet, execstat: ExecutorStatus): Promise {
return this.preMats.updateBase(baseSet, execstat).then(
() => this.postMats.update(baseSet, execstat)
);
}
}
class ToomMatHtmlContainer_MainSet {
baseAry: BaseSet[];
baseSelector: HTMLSelectElement;
progressBlock: HTMLElement;
body: ToomMatHtmlContainer_BodySet;
execstat: ExecutorStatus;
constructor(target: Node, baseAry: BaseSet[]) {
this.baseAry = baseAry;
var fragment = createDocumentFragment(), baseSelectorBlock = createParagraphElement(), baseSelector = createSelectElement();
baseAry.forEach((e) => {
baseSelector.appendChild(createOption(e.name,
"Toom-" + (.5 * e.base.length + .5 | 0) + "." + ((5 * e.base.length + 5) % 10) + " : " + BaseStr_snip(e.base)
));
});
baseSelectorBlock.appendChild(this.baseSelector = baseSelector);
fragment.appendChild(this.progressBlock = createParagraphElement());
fragment.appendChild(baseSelectorBlock);
this.body = new ToomMatHtmlContainer_BodySet(fragment);
target.appendChild(fragment);
(baseSelector.onchange = ((_this: ToomMatHtmlContainer_MainSet) => (ev?) => {
var selBase = _this.baseAry[_this.baseSelector.selectedIndex];
_this.update(selBase);
})(this))();
}
update(baseSet: BaseSet, execstat: ExecutorStatus = new ExecutorStatus()): Promise {
var _this = this, progress_p: HTMLElement, progress: HTMLElement;
return new Promise((callback, reject) => {
if (_this.execstat && _this.execstat !== execstat) {
_this.execstat.cancel();
}
_this.execstat = execstat;
progress_p = createParagraphElement();
progress_p.appendChild(createTextNode('Calculating inversion-matrix: '));
progress = createProgressElement();
progress.appendChild(createTextNode('in progress'));
progress.setAttribute('max', '65536');
progress_p.appendChild(progress);
replaceChildDom(_this.progressBlock, progress_p);
callback();
}).then(
() => _this.body.update(baseSet, execstat)
).then(baseSet.imat ? () => { } :
() => {
return new Promise(
(callback, reject) => {
var replot = () => _this.body.update(baseSet, execstat).then(() => { callback() }),
recalc = () =>
baseSet.pmat.LUPinversePromise(execstat, (value: number) => {
if (execstat.isCancel()) { return Promise.reject(new Error('abort calculation')) }
progress.setAttribute('value', (value * 65536 | 0) + '');
}).then((m) => { baseSet.imat = m; }).then(replot).then(() => { }, (e) => { reject(e) });
loadMatrix(baseSet).then(() => baseSet.imat ? replot() : recalc(), recalc);
}
);
}
).then(() => { hideChildElement(_this.progressBlock) });
}
}
(() => {
var ifmt = (i: number): string => (i | 0) + "." + (i * 10 % 10 | 0),
baseex: OneBase[][] = [
[[-1, 1], [0, 1], [1, 0]],
[[-1, 1], [0, 1], [1, 1], [1, 0]],
[[-2, 1], [-1, 1], [0, 1], [1, 1], [1, 0]],
[[-2, 1], [-1, 1], [0, 1], [1, 1], [2, 1], [1, 0]],
[[-1, 2], [-2, 1], [-1, 1], [0, 1], [1, 1], [2, 1], [1, 0]],
[[-1, 2], [-2, 1], [-1, 1], [0, 1], [1, 1], [2, 1], [1, 2], [1, 0]],
[[1, 0], [10, 1], [1, 1], [-1, 1], [0, 1]],
[[1, 0], [-10, 1], [1, 1], [-1, 1], [0, 1]],
[[1, 0], [10, 1], [-10, 1], [1, 1], [-1, 1], [0, 1]],
[[1, 0], [-1, 10], [10, 1], [-10, 1], [1, 1], [-1, 1], [0, 1]],
[[1, 0], [1, 10], [-1, 10], [10, 1], [-10, 1], [1, 1], [-1, 1], [0, 1]]
];
[1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 9.5, 10.0, 10.5, 12.0, 12.5, 16.0, 16.5, 20.0, 20.5].forEach((i) => {
var b: OneBase[] = genBaseA(i), s: BaseSet = {
name: "baseA_" + ifmt(i),
base: b,
pmat: toomPmat(b),
imat: undefined
};
baseAry.push(s);
});
[5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 9.5, 10.0, 10.5, 12.0, 12.5, 16.0, 16.5, 20.0, 20.5, 24.0, 24.5, 36.0, 36.5, 44.0, 44.5, 56.0, 56.5, 64.0, 64.5].forEach((i) => {
var b: OneBase[] = genBaseB(i), s: BaseSet = {
name: "baseB_" + ifmt(i),
base: b,
pmat: toomPmat(b),
imat: undefined
};
baseAry.push(s);
});
[7.0, 7.5, 8.0, 8.5, 9.0, 9.5, 10.0, 10.5, 12.0, 12.5, 16.0, 16.5, 20.0, 20.5, 24.0, 24.5, 36.0, 36.5, 44.0, 44.5, 56.0, 56.5, 64.0, 64.5].forEach((i) => {
var b: OneBase[] = genBaseC(i), s: BaseSet = {
name: "baseC_" + ifmt(i),
base: b,
pmat: toomPmat(b),
imat: undefined
};
baseAry.push(s);
});
baseex.forEach((b) => {
var i: number = .5 * b.length + .5, s: BaseSet = {
name: "baseX_" + ifmt(i) + "_" + b.map((e) => e[0] + "/" + e[1]).join("_"),
base: b,
pmat: toomPmat(b),
imat: undefined
};
baseAry.push(s);
});
})();
window.onload = () => {
new ToomMatHtmlContainer_MainSet(getElementById('toomParamMain'), baseAry);
};
}