morilib-apl
Version:
an APL Interpreter
1,631 lines (1,431 loc) • 104 kB
JavaScript
/*
* Morilib APL
*
* Copyright (c) 2019 Yuichiro MORIGUCHI
*
* This software is released under the MIT License.
* http://opensource.org/licenses/mit-license.php
**/
(function(root) {
var undef = void 0;
/*
* Reference:
* http://my.fit.edu/~gabdo/gamma.txt
*/
var GAMMA_COEFFS = [
0.99999999999999709182,
57.156235665862923517,
-59.597960355475491248,
14.136097974741747174,
-0.49191381609762019978,
.33994649984811888699e-4,
.46523628927048575665e-4,
-.98374475304879564677e-4,
.15808870322491248884e-3,
-.21026444172410488319e-3,
.21743961811521264320e-3,
-.16431810653676389022e-3,
.84418223983852743293e-4,
-.26190838401581408670e-4,
.36899182659531622704e-5
];
var LOG_SQRT_2PI = Math.log(2 * Math.PI) / 2;
var monadic = {
"-": function(array) {
return map(array, function(x) { return -x; }, isNumber);
},
"×": function(array) {
return map(array, function(x) {
return x > 0 ? 1 : x < 0 ? -1 : 0;
}, isNumber);
},
"÷": function(array) {
return map(array, function(x) { return 1 / x; }, isNumber);
},
"ι": function(object1) {
if(isNumber(object1)) {
return iota(object1, 1, 1);
} else if(isString(object1)) {
throw new Error("DOMAIN ERROR");
} else {
throw new Error("NOT SUPPORTED");
}
},
"ρ": function(object1) {
return scalarize(rho(object1));
},
"〆": function(object1) {
return transpose(object1);
},
"*": function(array) {
return map(array, function(x) { return Math.exp(x); }, isNumber);
},
"★": function(array) {
return monadic["*"](array);
},
"☆": function(array) {
return map(array, function(x) {
if(x <= 0) {
throw new Error("DOMAIN ERROR");
}
return Math.log(x);
}, isNumber);
},
"|": function(array) {
return map(array, function(x) { return Math.abs(x); }, isNumber);
},
"「": function(array) {
return map(array, function(x) { return Math.ceil(x); }, isNumber);
},
"」": function(array) {
return map(array, function(x) { return Math.floor(x); }, isNumber);
},
"〇": function(array) {
return map(array, function(x) { return Math.PI * x; }, isNumber);
},
"~": function(array) {
return map(array, function(x) { return x === 0 ? 1 : 0; });
},
"~": function(array) {
return monadic["~"](array);
},
",": function(array) {
return toVector(array);
},
"?": function(array) {
return map(array, function(x) {
if(!(isInteger(x) && x >= 1)) {
throw new Error("DOMAIN ERROR");
}
return Math.floor(Math.random() * x + 1);
});
},
"!": function(array) {
return map(array, function(x) { return gamma(x + 1); }, isNumber);
},
"♯": function(vector) {
return sortVector(vector, false);
},
"♭": function(vector) {
return sortVector(vector, true);
},
"※": function(matrix) {
matrixLib.checkDiag(matrix);
return matrixLib.solveGaussJordan(matrix, matrixLib.makeUnit(matrix.length, matrix.length));
},
"◆": function(array) {
return toStringArray(array, null);
}
};
var dyadic = {
"+": function(object1, object2) {
return map2Scalar(object1, object2, function(x, y) { return x + y; }, isNumber);
},
"-": function(object1, object2) {
return map2Scalar(object1, object2, function(x, y) { return x - y; }, isNumber);
},
"×": function(object1, object2) {
return map2Scalar(object1, object2, function(x, y) { return x * y; }, isNumber);
},
"÷": function(object1, object2) {
return map2Scalar(object1, object2, function(x, y) { return x / y; }, isNumber);
},
"ι": function(vector1, object2) {
checkVectorByFunction(vector1, function(x) { return true; });
return map(object2, function(x) {
var result = vector1.indexOf(x);
return result < 0 ? vector1.length + 1 : result + 1;
});
},
"ρ": function(vector1, vector2) {
var vec1 = isArray(vector1) ? vector1 : [vector1],
vec2 = isArray(vector2) ? toVector(vector2) : [vector2];
function gendim(index, dim) {
var result = [],
resultValue,
i,
nowIndex = index;
if(dim >= vec1.length) {
return {
value: isArray(vec2) ? vec2[index] : vec2,
index: index + 1
};
} else {
for(i = 0; i < vec1[dim]; i++) {
resultValue = gendim(index, dim + 1);
index = resultValue.index % vec2.length;
result[i] = resultValue.value;
}
return {
value: result,
index: index
};
}
}
checkVectorByFunction(vec1, function(x) {
return isInteger(x) && x >= 0;
});
if(vec2.length === 0) {
return 0;
} else if(vec1.length === 0) {
return vec2[0];
} else {
return gendim(0, 0).value;
}
},
"*": function(object1, object2) {
function pow(x, y) {
var res,
i;
if(isInteger(y)) {
if(y > 0) {
res = x;
for(i = 1; i < y; i++) {
res *= x;
}
return res;
} else if(y === 0) {
return 1;
} else if(y < 0) {
res = 1 / x;
for(i = 1; i < -y; i++) {
res /= x;
}
return res;
}
} else if(y > 0) {
return Math.pow(x, y);
} else {
throw new Error("DOMAIN ERROR");
}
}
return map2Scalar(object1, object2, function(x, y) { return pow(x, y); }, isNumber);
},
"★": function(object1, object2) {
return dyadic["*"](object1, object2);
},
"☆": function(object1, object2) {
function log(x, y) {
if(x <= 0 || y <= 0) {
throw new Error("DOMAIN ERROR");
}
return Math.log(y) / Math.log(x);
}
return map2Scalar(object1, object2, function(x, y) { return log(x, y); }, isNumber);
},
"|": function(object1, object2) {
return map2Scalar(object1, object2, function(x, y) {
if(x === 0) {
return y;
} else if(x > 0 && y >= 0) {
return y % x;
} else if(x > 0 && y <= 0) {
return y % x + x;
} else if(x < 0 && y > 0) {
return y % x + x;
} else {
return y % x;
}
}, isNumber);
},
"「": function(object1, object2) {
return map2Scalar(object1, object2, function(x, y) {
return x > y ? x : y;
}, isNumber);
},
"」": function(object1, object2) {
return map2Scalar(object1, object2, function(x, y) {
return x < y ? x : y;
}, isNumber);
},
"〇": function(object1, object2) {
var fn;
function fn0(x) {
if(x > 1) {
throw new Error("DOMAIN ERROR");
}
return Math.sqrt(1 - x * x);
}
function fnM1(x) {
if(x < -1 || x > 1) {
throw new Error("DOMAIN ERROR");
}
return Math.asin(x);
}
function fnM2(x) {
if(x < -1 || x > 1) {
throw new Error("DOMAIN ERROR");
}
return Math.acos(x);
}
function fnM4(x) {
if(x < 1) {
throw new Error("DOMAIN ERROR");
}
return Math.sqrt(-1 + x * x);
}
function fnM6(x) {
if(x < 1) {
throw new Error("DOMAIN ERROR");
}
return Math.acosh(x);
}
return map2Scalar(object1, object2, function(x, y) {
function getFn(anInt) {
if(!isInteger(anInt)) {
throw new Error("DOMAIN ERROR");
}
switch(anInt) {
case 0: return fn0;
case 1: return Math.sin;
case 2: return Math.cos;
case 3: return Math.tan;
case 4: return function(x) { return Math.sqrt(1 + x * x); };
case 5: return sinh;
case 6: return cosh;
case 7: return tanh;
case -1: return fnM1;
case -2: return fnM2;
case -3: return Math.atan;
case -4: return fnM4;
case -5: return Math.asinh ? Math.asinh : K;
case -6: return Math.acosh ? fnM6 : K;
case -7: return Math.atanh ? Math.atanh : K;
default: return K;
}
}
fn = getFn(x);
return fn(y);
}, isNumber);
},
"=": function(object1, object2) {
return map2Scalar(object1, object2, function(x, y) { return x === y ? 1 : 0 });
},
"≠": function(object1, object2) {
return map2Scalar(object1, object2, function(x, y) { return x !== y ? 1 : 0 });
},
"<": function(object1, object2) {
return map2Scalar(object1, object2, relCheck(function(x, y) { return x < y }), isNumber);
},
"≦": function(object1, object2) {
return map2Scalar(object1, object2, relCheck(function(x, y) { return x <= y }), isNumber);
},
">": function(object1, object2) {
return map2Scalar(object1, object2, relCheck(function(x, y) { return x > y }), isNumber);
},
"≧": function(object1, object2) {
return map2Scalar(object1, object2, relCheck(function(x, y) { return x >= y }), isNumber);
},
"^": function(object1, object2) {
return map2Scalar(object1, object2, function(x, y) { return x && y ? 1 : 0 });
},
"∧": function(object1, object2) {
return dyadic["^"](object1, object2);
},
"v": function(object1, object2) {
return map2Scalar(object1, object2, function(x, y) { return x || y ? 1 : 0 });
},
"∨": function(object1, object2) {
return dyadic["v"](object1, object2);
},
"†": function(object1, object2) {
return map2Scalar(object1, object2, function(x, y) { return !(x && y) ? 1 : 0 });
},
"‡": function(object1, object2) {
return map2Scalar(object1, object2, function(x, y) { return !(x || y) ? 1 : 0 });
},
"〆": function(vector1, array1) {
return substituteArray(vector1, array1);
},
"?": function(number1, number2) {
var extracted = [],
i,
value;
if(!isInteger(number1) || !isInteger(number2)) {
throw new Error("DOMAIN ERROR");
} else if(number1 < 0 || number2 < 0 || number1 > number2) {
throw new Error("DOMAIN ERROR");
}
for(i = 0; i < number1; i++) {
value = Math.floor(Math.random() * number2 + 1);
while(extracted.indexOf(value) >= 0) {
value = Math.floor(Math.random() * number2 + 1);
}
extracted.push(value);
}
return extracted;
},
"!": function(object1, object2) {
return map2Scalar(object1, object2, function(x, y) {
return gamma(y + 1) / gamma(x + 1) / gamma(y - x + 1);
}, isNumber);
},
"↑": function(object1, object2) {
return takeArray(object1, object2);
},
"↓": function(object1, object2) {
return dropArray(object1, object2);
},
"ε": function(object1, object2) {
return belongToArray(object1, object2);
},
"∈": function(object1, object2) {
return dyadic["ε"](object1, object2);
},
"⊥": function(object1, object2) {
return decodeArray(object1, object2);
},
"┴": function(object1, object2) {
return dyadic["⊥"](object1, object2);
},
"┬": function(object1, object2) {
return encodeArray(object1, object2);
},
"※": function(vector1, matrix2) {
var rho1 = rho(vector1),
rho2 = rho(matrix2);
matrixLib.checkMatrix(matrix2);
if(rho1.length !== 1) {
throw new Error("RANK ERROR");
} else if(rho2.length !== 2) {
throw new Error("RANK ERROR");
} else if(vector1.length !== matrix2.length) {
throw new Error("LENGTH ERROR");
}
if(matrixLib.isDiag(matrix2)) {
return matrixLib.solve(matrix2, vector1);
} else {
return leastSquare(matrix2, vector1);
}
},
"◆": function(vector1, object2) {
var vec;
if(isArray(vector1) && vector1.length > 2) {
throw new Error("LENGTH ERROR");
}
return toStringArray(object2, vector1);
}
};
var operator = {
".": function(fn1, fn2) {
return function(array1, array2) {
var result = [],
rhoArray1,
rhoArray2,
rhoArray2a;
function generate1(indicesArray1, rhoArray1, indicesArray2, rhoArray2) {
var fold1,
i;
if(rhoArray1.length > 1) {
for(i = 0; i < rhoArray1[0]; i++) {
generate1(indicesArray1.concat([i]), rhoArray1.slice(1), indicesArray2, rhoArray2);
}
} else if(rhoArray2.length > 0) {
for(i = 0; i < rhoArray2[0]; i++) {
generate1(indicesArray1, rhoArray1, indicesArray2.concat([i]), rhoArray2.slice(1));
}
} else {
fold1 = [];
if(rhoArray1[0] !== rhoArray2a) {
throw new Error("LENGTH ERROR");
}
for(i = 0; i < rhoArray2a; i++) {
fold1[i] = fn2(getIndex(array1, indicesArray1.concat([i])), getIndex(array2, [i].concat(indicesArray2)));
}
if(indicesArray1.length + indicesArray2.length > 0) {
setIndex(result, indicesArray1.concat(indicesArray2), fold(fold1, fn1));
} else {
result = fold(fold1, fn1);
}
}
}
function generateLeftScalar(scalar, indicesArray2, rhoArray2) {
var fold1,
i;
if(rhoArray2.length > 0) {
for(i = 0; i < rhoArray2[0]; i++) {
generateLeftScalar(scalar, indicesArray2.concat([i]), rhoArray2.slice(1));
}
} else {
fold1 = [];
for(i = 0; i < rhoArray2a; i++) {
fold1[i] = fn2(scalar, getIndex(array2, [i].concat(indicesArray2)));
}
if(indicesArray2.length > 0) {
setIndex(result, indicesArray2, fold(fold1, fn1));
} else {
result = fold(fold1, fn1);
}
}
}
function generateRightScalar(array1, scalar) {
var result = [],
fold1,
i;
if(!isArray(array1[0])) {
fold1 = [];
for(i = 0; i < array1.length; i++) {
fold1[i] = fn2(array1[i], scalar);
}
return fold(fold1, fn1);
} else {
for(i = 0; i < array1.length; i++) {
result[i] = generateRightScalar(array1[i], scalar);
}
return result;
}
}
if(!isArray(array1) && !isArray(array2)) {
return fn2(array1, array2);
} else if(!isArray(array1)) {
if(array1.length === 0) {
return 0;
} else {
rhoArray2 = rho(array2);
rhoArray2a = rhoArray2[0];
generateLeftScalar(array1, [], rhoArray2.slice(1));
return result;
}
} else if(!isArray(array2)) {
if(array2.length === 0) {
return 0;
} else {
return generateRightScalar(array1, array2);
}
} else if(array1.length === 0 && array2.length === 0) {
return 0;
} else if(array1.length === 0 || array2.length === 0) {
throw new Error("LENGTH ERROR");
} else {
rhoArray1 = rho(array1);
rhoArray2 = rho(array2);
rhoArray2a = rhoArray2[0];
generate1([], rhoArray1, [], rhoArray2.slice(1));
return result;
}
};
}
};
var MAP_APL_CHAR = {
"\u00af": " ̄",
"\u2206": "△",
"\u220a": "∈",
"\u2218": "・",
"\u2223": "|",
"\u223c": "~",
"\u2264": "≦",
"\u2265": "≧",
"\u2308": "「",
"\u230a": "」",
"\u22a4": "┬",
"\u22c6": "★",
"\u2339": "※",
"\u233d": "φ",
"\u233f": "/[1]",
"\u2340": "\\[1]",
"\u2349": "〆",
"\u234b": "♯",
"\u234e": "♪",
"\u2352": "♭",
"\u2355": "◆",
"\u2358": "!",
"\u235f": "☆",
"\u2372": "†",
"\u2371": "‡",
"\u2373": "ι",
"\u2374": "ρ"
};
var MAP_FULLWIDTH = {
"1": "1",
"2": "2",
"3": "3",
"4": "4",
"5": "5",
"6": "6",
"7": "7",
"8": "8",
"9": "9",
"0": "0",
"+": "+",
"-": "-"
};
var MAP_ASCII_STR = {
"~": " ̄",
"*": "×",
"/": "÷",
"max": "「",
"min": "」",
"**": "★",
"log": "☆",
"tri": "〇",
">=": "≧",
"<=": "≦",
"!=": "≠",
"and": "∧",
"or": "∨",
"nand": "†",
"nor": "‡",
"outer": "・",
"rho": "ρ",
"take": "↑",
"drop": "↓",
"/-": "/[1]",
"\\-": "\\[1]",
"rotate": "φ",
"rotate1": "φ[1]",
"transpose": "〆",
"iota": "ι",
"in": "∈",
"asc": "♯",
"desc": "♭",
"domino": "※",
"encode": "┬",
"decode": "⊥",
"eval": "♪",
"tostring": "◆",
"<-": "←"
};
function K(x) {
return x;
}
function isObject(anObject) {
return typeof anObject === "object" && anObject !== null;
}
function isNumber(anObject) {
return typeof anObject === "number";
}
function isString(anObject) {
return typeof anObject === "string";
}
function isArray(anObject) {
return Object.prototype.toString.call(anObject) === '[object Array]';
}
function isInteger(anObject) {
return typeof anObject === 'number' && isFinite(anObject) && Math.floor(anObject) === anObject;
}
function charArrayToString(anObject) {
var result = "",
i;
if(!isArray(anObject)) {
throw new Error("DOMAIN ERROR");
}
for(i = 0; i < anObject.length; i++) {
if(isArray(anObject[i])) {
throw new Error("RANK ERROR");
} else if(!isString(anObject[i]) || anObject[i].length !== 1) {
throw new Error("DOMAIN ERROR");
}
result += anObject[i];
}
return result;
}
function stringToCharArray(aString) {
var result = [],
i;
for(i = 0; i < aString.length; i++) {
result[i] = aString.charAt(i);
}
return result;
}
function getNumberExponent(aNumber) {
var matched,
result;
if(!(matched = /(-?[0-9]*(?:\.[0-9]+)?)[eE]([\+\-][0-9]+)$/.exec(aNumber.toExponential()))) {
return NaN;
}
result = matched[2].replace(/^\+/, "");
return [parseFloat(matched[1]), parseInt(result)];
}
function sinh(x) {
var y = Math.exp(x);
return (y - 1 / y) / 2;
}
function cosh(x) {
var y = Math.exp(x);
return (y + 1 / y) / 2;
}
function tanh(x) {
var y;
if(x === Infinity) {
return 1;
} else if(x === -Infinity) {
return -1;
} else {
y = Math.exp(2 * x);
return (y - 1) / (y + 1);
}
}
/*
* Reference:
* http://my.fit.edu/~gabdo/gamma.txt
*/
function lnGamma0(x) {
var g = 607.0 / 128.0,
r = 0,
s = 0,
t,
k;
if(x > 0) {
for(k = GAMMA_COEFFS.length - 1; k > 0; k--) {
s += GAMMA_COEFFS[k] / (x + k);
}
s += GAMMA_COEFFS[0];
t = x + g + 0.5;
r = (x + 0.5) * Math.log(t);
r -= t;
r += LOG_SQRT_2PI;
r += Math.log(s / x);
return r;
} else {
return NaN;
}
}
function gamma(x) {
function frac(n) {
var i,
result = 1;
for(i = 2; i <= n; i++) {
result *= i;
}
return result;
}
function sum(n) {
var i,
result = 0;
for(i = 1; i < n; i++) {
result += i;
}
return result;
}
if(isInteger(x)) {
if(x >= 1) {
return frac(x - 1);
} else if(x === 0) {
return 1;
} else {
return Infinity;
}
} else if(x > 1) {
return Math.exp(lnGamma0(x));
} else if(x > 0 && x < 1) {
return gamma(x + 1) / x;
} else {
return -Math.PI / Math.sin(Math.PI * x) / x / gamma(-x);
}
}
var matrixLib = {
isDiag: function(matrix) {
if(!isArray(matrix) && matrix.length < 2) {
throw new Error("RANK ERROR");
}
for(i = 0; i < matrix.length; i++) {
if(matrix[i].length !== matrix.length) {
return false;
}
}
return true;
},
checkMatrix: function(matrix) {
var length = -1;
if(!isArray(matrix) && matrix.length < 2) {
throw new Error("RANK ERROR");
}
for(i = 0; i < matrix.length; i++) {
checkVectorByFunction(matrix[i], function(x) { return isNumber(x); });
if(length < 0) {
length = matrix[i].length;
} else if(matrix[i].length !== length) {
throw new Error("LENGTH ERROR");
}
}
},
checkDiag: function(matrix) {
if(!isArray(matrix) && matrix.length < 2) {
throw new Error("RANK ERROR");
}
for(i = 0; i < matrix.length; i++) {
checkVectorByFunction(matrix[i], function(x) { return isNumber(x); });
if(matrix[i].length !== matrix.length) {
throw new Error("LENGTH ERROR");
}
}
},
makeZero: function(sizeI, sizeJ) {
var i,
j,
result = [];
for(i = 0; i < sizeI; i++) {
result[i] = [];
for(j = 0; j < sizeJ; j++) {
result[i][j] = 0;
}
}
return result;
},
makeUnit: function(sizeI, sizeJ) {
var i,
j,
result = [];
for(i = 0; i < sizeI; i++) {
result[i] = [];
for(j = 0; j < sizeJ; j++) {
result[i][j] = i === j ? 1 : 0;
}
}
return result;
},
invertPermutation: function(matrix, permutation) {
var result = [],
i;
for(i = 0; i < permutation.length; i++) {
result[permutation[i]] = matrix[i];
}
return result;
},
columnPermutation: function(matrix, permutation) {
var source = deepcopy(matrix),
result = [],
i,
j;
for(i = 0; i < permutation.length; i++) {
result[i] = [];
for(j = 0; j < permutation.length; j++) {
result[i][permutation[j]] = source[i][j];
}
}
return result;
},
factorizeLU: function(matrix) {
var i,
j,
k,
m,
n,
A,
L,
U,
tA,
P = iota(matrix.length, 0, 1);
matrixLib.checkDiag(matrix);
A = deepcopy(matrix);
L = matrixLib.makeZero(matrix.length, matrix.length);
U = matrixLib.makeZero(matrix.length, matrix.length);
for(k = 0; k < A.length; k++) {
if(A[k][k] === 0) {
for(m = 0; m < A.length; m++) {
if(A[k][m] !== 0) {
tmp = P[m]; P[m] = P[k]; P[k] = tmp;
for(n = 0; n < A.length; n++) {
tmp = A[n][m]; A[n][m] = A[n][k]; A[n][k] = tmp;
}
break;
}
}
if(m >= matrix.length) {
throw new Error("DOMAIN ERROR");
}
}
for(i = 0; i < A[0].length; i++) {
if(i < k) {
L[i][k] = U[k][i] = 0;
} else if(i === k) {
L[i][k] = 1;
U[k][i] = A[k][k];
} else {
L[i][k] = A[i][k] / A[k][k];
U[k][i] = A[k][i];
}
}
tA = deepcopy(A);
for(i = 0; i < A.length; i++) {
A[i][k] = A[k][i] = 0;
}
for(i = k + 1; i < A.length; i++) {
for(j = k + 1; j < A[0].length; j++) {
A[i][j] = tA[i][j] - L[i][k] * U[k][j];
}
}
}
return {
P: P,
L: L,
U: U
};
},
solve: function(matrix, vector) {
var i,
j,
lu,
L,
U,
y = [],
V,
result = [];
lu = matrixLib.factorizeLU(matrix);
L = lu.L;
U = lu.U;
V = vector.slice();
for(i = 0; i < matrix.length; i++) {
y[i] = 0;
for(j = 0; j < i; j++) {
y[i] += L[i][j] * y[j];
}
y[i] = (V[i] - y[i]);
}
for(i = matrix.length - 1; i >= 0; i--) {
result[i] = 0;
for(j = i; j < V.length; j++) {
result[i] += U[i][j] * result[j];
}
result[i] = (y[i] - result[i]) / U[i][i];
}
return matrixLib.invertPermutation(result, lu.P);
},
solveGaussJordan: function(matrix, source) {
var i,
j,
k,
val,
elm,
tmp,
permutation = iota(matrix.length, 0, 1),
m = deepcopy(matrix),
v = deepcopy(source);
matrixLib.checkDiag(matrix);
for(i = 0; i < m.length; i++) {
val = m[i][i];
if(val === 0) {
for(j = 0; j < matrix.length; j++) {
if(matrix[permutation[j]][i] !== 0) {
tmp = permutation[j];
permutation[j] = permutation[i];
permutation[i] = tmp;
tmp = m[j];
m[j] = m[i];
m[i] = tmp;
val = m[i][i];
break;
}
}
if(j >= matrix.length) {
throw new Error("DOMAIN ERROR");
}
}
for(j = 0; j < m[i].length; j++) {
if(i !== j) {
elm = m[j][i] / val;
for(k = 0; k < m.length; k++) {
m[j][k] = m[j][k] - (m[i][k] * elm);
}
if(isArray(v[0])) {
for(k = 0; k < v.length; k++) {
v[j][k] = v[j][k] - (v[i][k] * elm);
}
} else {
v[j] = v[j] - (v[i] * elm);
}
}
}
for(j = 0; j < m[i].length; j++) {
if(i === j) {
for(k = 0; k < m.length; k++) {
if(i === k) {
m[j][k] = 1;
} else {
m[j][k] = m[j][k] / val;
}
}
if(isArray(v[0])) {
for(k = 0; k < v.length; k++) {
v[j][k] = v[j][k] / val;
}
} else {
v[j] = v[j] / val;
}
}
}
}
return matrixLib.columnPermutation(v, permutation);
}
};
function leastSquare(matrix, vector) {
var normalMatrix = [],
normalVector = [],
i,
j,
k;
for(i = 0; i < matrix[0].length; i++) {
normalMatrix[i] = [];
for(j = 0; j < matrix[0].length; j++) {
normalMatrix[i][j] = 0;
for(k = 0; k < matrix.length; k++) {
normalMatrix[i][j] += matrix[k][i] * matrix[k][j];
}
}
}
for(i = 0; i < matrix[0].length; i++) {
normalVector[i] = 0;
for(k = 0; k < matrix.length; k++) {
normalVector[i] += matrix[k][i] * vector[k];
}
}
return matrixLib.solve(normalMatrix, normalVector);
}
function deepcopy(anObject) {
var result;
function copyAll() {
var i;
for(i in anObject) {
if(anObject.hasOwnProperty(i)) {
result[i] = deepcopy(anObject[i]);
}
}
}
if(isArray(anObject)) {
result = [];
copyAll();
return result;
} else if(typeof anObject === 'object' && anObject !== null) {
result = {};
copyAll();
return result;
} else {
return anObject;
}
}
function relCheck(f) {
return function(x, y) {
if(isNumber(x) && isNumber(y)) {
return f(x, y) ? 1 : 0;
} else {
throw new Error("DOMAIN ERROR");
}
}
}
function mapHomomorphism(mapping, source) {
var result = "",
match,
i;
for(i = 0; i < source.length; i++) {
if((match = mapping[source.charAt(i)]) !== undef) {
result += match;
} else {
result += source.charAt(i);
}
}
return result;
}
function scalarize(anArray) {
if(anArray.length === 1 && !isArray(anArray[0])) {
return anArray[0];
} else {
return anArray;
}
}
function getIndex(array1, indexVector) {
if(isArray(array1)) {
if(indexVector.length === 0) {
return array1;
} else if(!isInteger(indexVector[0])) {
throw new Error("DOMAIN ERROR");
} else if(indexVector[0] < 0 || indexVector[0] >= array1.length) {
throw new Error("INDEX ERROR");
}
return getIndex(array1[indexVector[0]], indexVector.slice(1));
} else {
return array1;
}
}
function setIndex(array1, indexVector, value) {
if(array1[indexVector[0]] === undef) {
array1[indexVector[0]] = [];
}
if(!isInteger(indexVector[0])) {
throw new Error("DOMAIN ERROR");
} else if(indexVector[0] < 0 || indexVector[0] >= array1.length) {
throw new Error("INDEX ERROR");
}
if(indexVector.length > 1) {
setIndex(array1[indexVector[0]], indexVector.slice(1), value);
} else {
array1[indexVector[0]] = value;
}
}
function checkVectorByFunction(vector0, fn) {
var i;
if(!isArray(vector0)) {
throw new Error("RANK ERROR");
}
for(i = 0; i < vector0.length; i++) {
if(isArray(vector0[i])) {
throw new Error("RANK ERROR");
} else if(!fn(vector0[i])) {
throw new Error("DOMAIN ERROR");
}
}
}
function checkArrayByFunction(array0, errorMsg, fn) {
var i;
if(isArray(array0)) {
for(i = 0; i < array0.length; i++) {
checkArrayByFunction(array0[i], errorMsg, fn);
}
} else {
if(!fn(array0)) {
throw new Error(errorMsg);
}
}
}
function transpose(array1) {
var result = [];
function walk(array1, indexVector) {
var i;
if(isArray(array1)) {
for(i = 0; i < array1.length; i++) {
walk(array1[i], indexVector.concat([i]));
}
} else {
setIndex(result, indexVector.reverse(), array1);
}
}
if(isArray(array1)) {
walk(array1, []);
return result;
} else {
return array1;
}
}
function substituteArray(vector, array1) {
var result = [],
vec = isArray(vector) ? vector : [vector],
rankVector = rho(array1),
inIndices = [],
max;
function checkVector(vector) {
var i,
j,
max = 0;
for(i = 0; i < vector.length; i++) {
if(isArray(vector[i])) {
throw new Error("RANK ERROR");
} else if(!isInteger(vector[i])) {
throw new Error("DOMAIN ERROR");
}
max = max < vector[i] ? vector[i] : max;
}
if(max <= 0 || max > vector.length) {
throw new Error("DOMAIN ERROR");
}
outer: for(i = 1; i <= max; i++) {
for(j = 0; j < vector.length; j++) {
if(vector[j] === i) {
continue outer;
}
}
throw new Error("DOMAIN ERROR");
}
return max;
}
function subst(outIndices) {
var i,
j,
dest;
if(outIndices.length === max) {
setIndex(result, outIndices, getIndex(array1, inIndices));
} else {
dest = vec.indexOf(outIndices.length + 1);
for(i = 0; i < rankVector[dest]; i++) {
for(j = 0; j < vec.length; j++) {
if(vec[j] === outIndices.length + 1) {
inIndices[j] = i;
}
}
subst(outIndices.concat([i]));
}
}
}
max = checkVector(vec);
if(vec.length !== rankVector.length) {
throw new Error("LENGTH ERROR");
} else if(rankVector.length === 0) {
return array1;
}
subst([]);
return result;
}
function foldOperator(operator) {
return function(axis) {
if(axis !== null && !isInteger(axis)) {
throw new Error("AXIS ERROR");
}
return function(array1) {
var rhoVector = rho(array1),
destAxis;
function foldop(array0, level) {
var i,
result;
if(!isArray(array0)) {
return array0;
} else if(level === destAxis) {
for(i = 0; i < array0.length; i++) {
if(i > 0) {
result = operator(result, foldop(array0[i], level + 1));
} else {
result = foldop(array0[i], level + 1);
}
}
} else {
result = [];
for(i = 0; i < array0.length; i++) {
result[i] = foldop(array0[i], level + 1);
}
}
return result;
}
if(!isArray(array1)) {
return array1;
} else if(array1.length === 0) {
return 0;
} else {
destAxis = axis === null ? rho(rhoVector)[0] : axis;
if(!isInteger(destAxis) || destAxis < 1 || destAxis > rhoVector.length) {
throw new Error("AXIS ERROR");
}
return foldop(array1, 1);
}
};
};
}
function scanOperator(operator) {
return function(axis) {
if(axis !== null && !isInteger(axis)) {
throw new Error("AXIS ERROR");
}
return function(array1) {
var rhoVector = rho(array1),
destAxis;
function foldop(array0, level) {
var i,
result;
if(!isArray(array0)) {
return array0;
} else if(level === destAxis) {
result = [];
for(i = 0; i < array0.length; i++) {
if(i > 0) {
result[i] = operator(result[i - 1], foldop(array0[i], level + 1));
} else {
result[i] = foldop(array0[i], level + 1);
}
}
} else {
result = [];
for(i = 0; i < array0.length; i++) {
result[i] = foldop(array0[i], level + 1);
}
}
return result;
}
if(!isArray(array1)) {
return array1;
} else if(array1.length === 0) {
return [];
} else {
destAxis = axis === null ? rho(rhoVector)[0] : axis;
if(!isInteger(destAxis) || destAxis < 1 || destAxis > rhoVector.length) {
throw new Error("AXIS ERROR");
}
return foldop(array1, 1);
}
};
};
}
function compressArray(vector, array1, axis) {
var rhoVector,
destAxis;
function comp(array0, level) {
var result = [],
i;
if(!isArray(array0)) {
return array0;
} else if(level === destAxis) {
if(vector.length !== array0.length) {
throw new Error("LENGTH ERROR");
}
for(i = 0; i < vector.length; i++) {
if(vector[i] !== 0) {
result.push(comp(array0[i], level + 1));
}
}
} else {
for(i = 0; i < array0.length; i++) {
result[i] = comp(array0[i], level + 1);
}
}
return result;
}
function compScalar(scalar) {
var result = [],
i;
for(i = 0; i < vector.length; i++) {
if(vector[i] !== 0) {
result.push(scalar);
}
}
return result;
}
function replicate(array0, times, level) {
var result = [],
i,
j;
if(!isArray(array0)) {
return array0;
} else if(level === destAxis) {
for(i = 0; i < array0.length; i++) {
for(j = 0; j < times; j++) {
result[i * times + j] = replicate(array0[i], times, level + 1);
}
}
} else {
for(i = 0; i < array0.length; i++) {
result[i] = replicate(array0[i], times, level + 1);
}
}
return result;
}
function replicateScalar(scalar, times) {
var result = [],
i;
for(i = 0; i < times; i++) {
result.push(scalar);
}
return result;
}
if(axis !== null && !isInteger(axis)) {
throw new Error("AXIS ERROR");
} else if(vector.length === 0 && array1.length === 0) {
return [];
} else if(isNumber(vector)) {
if(!isArray(array1)) {
return replicateScalar(array1, vector);
} else if(array1.length === 0) {
return [];
} else {
rhoVector = rho(array1);
destAxis = axis === null ? rho(rhoVector)[0] : axis;
if(!isInteger(destAxis) || destAxis < 1 || destAxis > rhoVector.length) {
throw new Error("AXIS ERROR");
}
return replicate(array1, vector, 1);
}
} else {
checkVectorByFunction(vector, function(x) { return true; });
if(!isArray(array1)) {
return compScalar(array1);
} else if(array1.length === 0) {
throw new Error("LENGTH ERROR");
} else {
rhoVector = rho(array1);
destAxis = axis === null ? rho(rhoVector)[0] : axis;
if(!isInteger(destAxis) || destAxis < 1 || destAxis > rhoVector.length) {
throw new Error("AXIS ERROR");
}
return comp(array1, 1);
}
}
}
function padArray(rhoVector, level, type) {
var result = [],
i;
if(level === rhoVector.length) {
return isNumber(type) ? 0 : " ";
} else {
for(i = 0; i < rhoVector[level]; i++) {
result[i] = padArray(rhoVector, level + 1, type[0]);
}
return result;
}
}
function expandArray(vector, array1, axis) {
var rhoVector,
rank,
destAxis;
function expand(array0, level) {
var result = [],
count = 0,
i;
if(!isArray(array0)) {
return array0;
} else if(level === destAxis) {
for(i = 0; i < vector.length; i++) {
if(vector[i] !== 0) {
result.push(expand(array0[count], level + 1));
count++;
} else {
result.push(padArray(rhoVector, level, array0[0]));
}
}
if(count !== array0.length) {
throw new Error("LENGTH ERROR");
}
} else {
for(i = 0; i < array0.length; i++) {
result[i] = expand(array0[i], level + 1);
}
}
return result;
}
function expandScalar(scalar) {
var result = [],
i;
for(i = 0; i < vector.length; i++) {
if(vector[i] !== 0) {
result.push(scalar);
} else if(isNumber(scalar)) {
result.push(0);
} else {
result.push(" ");
}
}
return result;
}
checkVectorByFunction(vector, function(x) { return true; });
if(axis !== null && !isInteger(axis)) {
throw new Error("AXIS ERROR");
} else if(!isArray(array1)) {
return expandScalar(array1);
} else if(vector.length === 0 && array1.length === 0) {
return [];
} else if(array1.length === 0) {
throw new Error("LENGTH ERROR");
} else {
rhoVector = rho(array1);
rank = rho(rhoVector)[0];
destAxis = axis === null ? rank : axis;
if(!isInteger(destAxis) || destAxis < 1 || destAxis > rhoVector.length) {
throw new Error("AXIS ERROR");
}
return expand(array1, 1);
}
}
function rotateArray(array1, array2, axis) {
var rhoVector,
rank,
destAxis,
arrayFixed2 = isArray(array2) ? array2 : [array2],
result = [];
function rotate1(indices, rotatedNum) {
var i,
inIndices,
indicesSet,
rotated;
inIndices = indices.slice();
inIndices.splice(destAxis - 1, 0, 0);
rotated = rotatedNum;
if(!isNumber(rotated)) {
throw new Error("DOMAIN ERROR");
}
rotated = rotated < 0 ? (rotated % rhoVector[destAxis - 1]) + rhoVector[destAxis - 1] : rotated;
inIndices[destAxis - 1] = rotated;
if(inIndices[destAxis - 1] >= rhoVector[destAxis - 1]) {
inIndices[destAxis - 1] -= rhoVec