From aa0249d458de26b8d34e7c7fe3f9b93fb80f2fd6 Mon Sep 17 00:00:00 2001 From: Sebastien Piquemal Date: Wed, 14 Aug 2013 15:00:12 +0400 Subject: [PATCH 1/4] fixed npm install, changed src to lib --- .npmignore | 1 - Jakefile.js | 6 +- README.md | 2 +- bower.json | 2 +- index.js | 117 +- package.json | 1 - src/constants.js | 23 - src/docs/constants/Infinity.js | 13 - src/docs/constants/LN10.js | 13 - src/docs/constants/LN2.js | 13 - src/docs/constants/LOG10E.js | 13 - src/docs/constants/LOG2E.js | 13 - src/docs/constants/NaN.js | 13 - src/docs/constants/SQRT1_2.js | 13 - src/docs/constants/SQRT2.js | 13 - src/docs/constants/e.js | 15 - src/docs/constants/false.js | 12 - src/docs/constants/i.js | 14 - src/docs/constants/pi.js | 13 - src/docs/constants/tau.js | 13 - src/docs/constants/true.js | 12 - src/docs/function/arithmetic/abs.js | 13 - src/docs/function/arithmetic/add.js | 19 - src/docs/function/arithmetic/ceil.js | 15 - src/docs/function/arithmetic/cube.js | 18 - src/docs/function/arithmetic/divide.js | 20 - src/docs/function/arithmetic/edivide.js | 19 - src/docs/function/arithmetic/emultiply.js | 19 - src/docs/function/arithmetic/epow.js | 17 - src/docs/function/arithmetic/equal.js | 21 - src/docs/function/arithmetic/exp.js | 20 - src/docs/function/arithmetic/fix.js | 16 - src/docs/function/arithmetic/floor.js | 15 - src/docs/function/arithmetic/gcd.js | 15 - src/docs/function/arithmetic/larger.js | 22 - src/docs/function/arithmetic/largereq.js | 20 - src/docs/function/arithmetic/lcm.js | 14 - src/docs/function/arithmetic/log.js | 23 - src/docs/function/arithmetic/log10.js | 19 - src/docs/function/arithmetic/mod.js | 20 - src/docs/function/arithmetic/multiply.js | 19 - src/docs/function/arithmetic/pow.js | 18 - src/docs/function/arithmetic/round.js | 19 - src/docs/function/arithmetic/sign.js | 17 - src/docs/function/arithmetic/smaller.js | 21 - src/docs/function/arithmetic/smallereq.js | 20 - src/docs/function/arithmetic/sqrt.js | 18 - src/docs/function/arithmetic/square.js | 21 - src/docs/function/arithmetic/subtract.js | 19 - src/docs/function/arithmetic/unary.js | 17 - src/docs/function/arithmetic/unequal.js | 22 - src/docs/function/arithmetic/xgcd.js | 14 - src/docs/function/complex/arg.js | 20 - src/docs/function/complex/conj.js | 20 - src/docs/function/complex/im.js | 20 - src/docs/function/complex/re.js | 20 - src/docs/function/construction/boolean.js | 20 - src/docs/function/construction/complex.js | 19 - src/docs/function/construction/matrix.js | 22 - src/docs/function/construction/number.js | 21 - src/docs/function/construction/range.js | 25 - src/docs/function/construction/string.js | 18 - src/docs/function/construction/unit.js | 20 - src/docs/function/matrix/concat.js | 20 - src/docs/function/matrix/det.js | 15 - src/docs/function/matrix/diag.js | 18 - src/docs/function/matrix/eye.js | 20 - src/docs/function/matrix/inv.js | 16 - src/docs/function/matrix/ones.js | 23 - src/docs/function/matrix/size.js | 18 - src/docs/function/matrix/squeeze.js | 17 - src/docs/function/matrix/subset.js | 23 - src/docs/function/matrix/transpose.js | 17 - src/docs/function/matrix/zeros.js | 22 - src/docs/function/probability/factorial.js | 15 - src/docs/function/probability/random.js | 13 - src/docs/function/probability/randomInt.js | 13 - src/docs/function/statistics/max.js | 22 - src/docs/function/statistics/min.js | 22 - src/docs/function/trigonometry/acos.js | 17 - src/docs/function/trigonometry/asin.js | 17 - src/docs/function/trigonometry/atan.js | 17 - src/docs/function/trigonometry/atan2.js | 21 - src/docs/function/trigonometry/cos.js | 20 - src/docs/function/trigonometry/cot.js | 17 - src/docs/function/trigonometry/csc.js | 17 - src/docs/function/trigonometry/sec.js | 17 - src/docs/function/trigonometry/sin.js | 20 - src/docs/function/trigonometry/tan.js | 19 - src/docs/function/units/in.js | 15 - src/docs/function/utils/clone.js | 16 - src/docs/function/utils/eval.js | 14 - src/docs/function/utils/format.js | 14 - src/docs/function/utils/help.js | 14 - src/docs/function/utils/import.js | 13 - src/docs/function/utils/typeof.js | 15 - src/docs/index.js | 110 -- src/exports.js | 30 - src/expr/Parser.js | 122 -- src/expr/Scope.js | 187 --- src/expr/Selector.js | 129 -- src/expr/node/AssignmentNode.js | 63 - src/expr/node/BlockNode.js | 85 -- src/expr/node/ConstantNode.js | 31 - src/expr/node/FunctionNode.js | 87 -- src/expr/node/MatrixNode.js | 155 --- src/expr/node/Node.js | 71 - src/expr/node/OperatorNode.js | 86 -- src/expr/node/ParamsNode.js | 129 -- src/expr/node/SymbolNode.js | 42 - src/expr/node/UpdateNode.js | 137 -- src/expr/node/handlers.js | 4 - src/expr/node/index.js | 12 - src/function/arithmetic/abs.js | 46 - src/function/arithmetic/add.js | 97 -- src/function/arithmetic/ceil.js | 48 - src/function/arithmetic/cube.js | 46 - src/function/arithmetic/divide.js | 109 -- src/function/arithmetic/edivide.js | 22 - src/function/arithmetic/emultiply.js | 22 - src/function/arithmetic/epow.js | 22 - src/function/arithmetic/equal.js | 71 - src/function/arithmetic/exp.js | 49 - src/function/arithmetic/fix.js | 48 - src/function/arithmetic/floor.js | 48 - src/function/arithmetic/gcd.js | 66 - src/function/arithmetic/larger.js | 71 - src/function/arithmetic/largereq.js | 71 - src/function/arithmetic/lcm.js | 71 - src/function/arithmetic/log.js | 63 - src/function/arithmetic/log10.js | 54 - src/function/arithmetic/mod.js | 74 - src/function/arithmetic/multiply.js | 210 --- src/function/arithmetic/pow.js | 105 -- src/function/arithmetic/round.js | 104 -- src/function/arithmetic/sign.js | 48 - src/function/arithmetic/smaller.js | 71 - src/function/arithmetic/smallereq.js | 71 - src/function/arithmetic/sqrt.js | 62 - src/function/arithmetic/square.js | 46 - src/function/arithmetic/subtract.js | 94 -- src/function/arithmetic/unary.js | 55 - src/function/arithmetic/unequal.js | 66 - src/function/arithmetic/xgcd.js | 45 - src/function/complex/arg.js | 47 - src/function/complex/conj.js | 48 - src/function/complex/im.js | 46 - src/function/complex/re.js | 47 - src/function/construction/boolean.js | 48 - src/function/construction/complex.js | 69 - src/function/construction/matrix.js | 30 - src/function/construction/number.js | 26 - src/function/construction/parser.js | 45 - src/function/construction/range.js | 73 - src/function/construction/string.js | 56 - src/function/construction/unit.js | 59 - src/function/matrix/concat.js | 115 -- src/function/matrix/det.js | 143 -- src/function/matrix/diag.js | 87 -- src/function/matrix/eye.js | 58 - src/function/matrix/inv.js | 185 --- src/function/matrix/ones.js | 36 - src/function/matrix/size.js | 50 - src/function/matrix/squeeze.js | 59 - src/function/matrix/subset.js | 205 --- src/function/matrix/transpose.js | 68 - src/function/matrix/zeros.js | 36 - src/function/probability/factorial.js | 58 - src/function/probability/random.js | 166 --- src/function/statistics/max.js | 103 -- src/function/statistics/min.js | 103 -- src/function/trigonometry/acos.js | 85 -- src/function/trigonometry/asin.js | 82 -- src/function/trigonometry/atan.js | 69 - src/function/trigonometry/atan2.js | 61 - src/function/trigonometry/cos.js | 60 - src/function/trigonometry/cot.js | 60 - src/function/trigonometry/csc.js | 61 - src/function/trigonometry/sec.js | 60 - src/function/trigonometry/sin.js | 59 - src/function/trigonometry/tan.js | 63 - src/function/units/in.js | 47 - src/function/utils/clone.js | 20 - src/function/utils/eval.js | 72 - src/function/utils/format.js | 32 - src/function/utils/help.js | 58 - src/function/utils/import.js | 120 -- src/function/utils/parse.js | 1334 ------------------- src/function/utils/select.js | 40 - src/function/utils/typeof.js | 20 - src/header.js | 26 - src/index.js | 116 -- src/options.js | 2 - src/shim.js | 183 --- src/type/Complex.js | 367 ----- src/type/Help.js | 92 -- src/type/Matrix.js | 680 ---------- src/type/Range.js | 255 ---- src/type/Unit.js | 725 ---------- src/type/collection.js | 228 ---- src/type/index.js | 7 - src/util/array.js | 221 --- src/util/boolean.js | 8 - src/util/error.js | 47 - src/util/index.js | 7 - src/util/number.js | 87 -- src/util/object.js | 131 -- src/util/string.js | 150 --- src/util/types.js | 66 - test/contstants.test.js | 2 +- test/expr/parser.test.js | 2 +- test/expr/scope.test.js | 2 +- test/function/arithmetic/abs.test.js | 2 +- test/function/arithmetic/add.test.js | 2 +- test/function/arithmetic/ceil.test.js | 2 +- test/function/arithmetic/cube.test.js | 2 +- test/function/arithmetic/divide.test.js | 2 +- test/function/arithmetic/edivide.test.js | 2 +- test/function/arithmetic/emultiply.test.js | 2 +- test/function/arithmetic/epow.test.js | 2 +- test/function/arithmetic/equal.test.js | 2 +- test/function/arithmetic/exp.test.js | 2 +- test/function/arithmetic/fix.test.js | 2 +- test/function/arithmetic/floor.test.js | 2 +- test/function/arithmetic/gcd.test.js | 2 +- test/function/arithmetic/larger.test.js | 2 +- test/function/arithmetic/largereq.test.js | 2 +- test/function/arithmetic/lcm.test.js | 2 +- test/function/arithmetic/log.test.js | 2 +- test/function/arithmetic/log10.test.js | 2 +- test/function/arithmetic/mod.test.js | 2 +- test/function/arithmetic/multiply.test.js | 2 +- test/function/arithmetic/pow.test.js | 2 +- test/function/arithmetic/round.test.js | 2 +- test/function/arithmetic/sign.test.js | 2 +- test/function/arithmetic/smaller.test.js | 2 +- test/function/arithmetic/smallereq.test.js | 2 +- test/function/arithmetic/sqrt.test.js | 2 +- test/function/arithmetic/square.test.js | 2 +- test/function/arithmetic/subtract.test.js | 2 +- test/function/arithmetic/unary.js | 2 +- test/function/arithmetic/unequal.test.js | 2 +- test/function/arithmetic/xgcd.test.js | 2 +- test/function/complex/arg.test.js | 2 +- test/function/complex/conj.test.js | 2 +- test/function/complex/im.test.js | 2 +- test/function/complex/re.test.js | 2 +- test/function/construction/boolean.test.js | 2 +- test/function/construction/complex.test.js | 2 +- test/function/construction/matrix.test.js | 2 +- test/function/construction/number.test.js | 2 +- test/function/construction/range.test.js | 2 +- test/function/construction/string.test.js | 2 +- test/function/construction/unit.test.js | 2 +- test/function/example.test.js | 2 +- test/function/matrix/concat.test.js | 2 +- test/function/matrix/det.test.js | 2 +- test/function/matrix/diag.test.js | 2 +- test/function/matrix/eye.test.js | 2 +- test/function/matrix/inv.test.js | 2 +- test/function/matrix/ones.test.js | 2 +- test/function/matrix/size.test.js | 2 +- test/function/matrix/squeeze.test.js | 2 +- test/function/matrix/subset.test.js | 2 +- test/function/matrix/transpose.test.js | 2 +- test/function/matrix/zeros.test.js | 2 +- test/function/probability/factorial.test.js | 2 +- test/function/probability/random.test.js | 2 +- test/function/statistics/max.test.js | 2 +- test/function/statistics/min.test.js | 2 +- test/function/trigonometry/acos.test.js | 2 +- test/function/trigonometry/asin.test.js | 2 +- test/function/trigonometry/atan.test.js | 2 +- test/function/trigonometry/atan2.test.js | 2 +- test/function/trigonometry/cos.test.js | 2 +- test/function/trigonometry/cot.test.js | 2 +- test/function/trigonometry/csc.test.js | 2 +- test/function/trigonometry/sec.test.js | 2 +- test/function/trigonometry/sin.test.js | 2 +- test/function/trigonometry/tan.test.js | 2 +- test/function/units/in.test.js | 2 +- test/function/utils/clone.test.js | 2 +- test/function/utils/eval.test.js | 2 +- test/function/utils/format.test.js | 2 +- test/function/utils/help.test.js | 2 +- test/function/utils/import.test.js | 2 +- test/function/utils/parse.test.js | 2 +- test/function/utils/select.test.js | 2 +- test/function/utils/typeof.test.js | 2 +- test/type/complex.test.js | 2 +- test/type/help.test.js | 2 +- test/type/matrix.test.js | 2 +- test/type/range.test.js | 2 +- test/type/unit.test.js | 2 +- test/util/array.test.js | 2 +- tools/jake-utils.js | 6 +- 296 files changed, 210 insertions(+), 13097 deletions(-) delete mode 100644 src/constants.js delete mode 100644 src/docs/constants/Infinity.js delete mode 100644 src/docs/constants/LN10.js delete mode 100644 src/docs/constants/LN2.js delete mode 100644 src/docs/constants/LOG10E.js delete mode 100644 src/docs/constants/LOG2E.js delete mode 100644 src/docs/constants/NaN.js delete mode 100644 src/docs/constants/SQRT1_2.js delete mode 100644 src/docs/constants/SQRT2.js delete mode 100644 src/docs/constants/e.js delete mode 100644 src/docs/constants/false.js delete mode 100644 src/docs/constants/i.js delete mode 100644 src/docs/constants/pi.js delete mode 100644 src/docs/constants/tau.js delete mode 100644 src/docs/constants/true.js delete mode 100644 src/docs/function/arithmetic/abs.js delete mode 100644 src/docs/function/arithmetic/add.js delete mode 100644 src/docs/function/arithmetic/ceil.js delete mode 100644 src/docs/function/arithmetic/cube.js delete mode 100644 src/docs/function/arithmetic/divide.js delete mode 100644 src/docs/function/arithmetic/edivide.js delete mode 100644 src/docs/function/arithmetic/emultiply.js delete mode 100644 src/docs/function/arithmetic/epow.js delete mode 100644 src/docs/function/arithmetic/equal.js delete mode 100644 src/docs/function/arithmetic/exp.js delete mode 100644 src/docs/function/arithmetic/fix.js delete mode 100644 src/docs/function/arithmetic/floor.js delete mode 100644 src/docs/function/arithmetic/gcd.js delete mode 100644 src/docs/function/arithmetic/larger.js delete mode 100644 src/docs/function/arithmetic/largereq.js delete mode 100644 src/docs/function/arithmetic/lcm.js delete mode 100644 src/docs/function/arithmetic/log.js delete mode 100644 src/docs/function/arithmetic/log10.js delete mode 100644 src/docs/function/arithmetic/mod.js delete mode 100644 src/docs/function/arithmetic/multiply.js delete mode 100644 src/docs/function/arithmetic/pow.js delete mode 100644 src/docs/function/arithmetic/round.js delete mode 100644 src/docs/function/arithmetic/sign.js delete mode 100644 src/docs/function/arithmetic/smaller.js delete mode 100644 src/docs/function/arithmetic/smallereq.js delete mode 100644 src/docs/function/arithmetic/sqrt.js delete mode 100644 src/docs/function/arithmetic/square.js delete mode 100644 src/docs/function/arithmetic/subtract.js delete mode 100644 src/docs/function/arithmetic/unary.js delete mode 100644 src/docs/function/arithmetic/unequal.js delete mode 100644 src/docs/function/arithmetic/xgcd.js delete mode 100644 src/docs/function/complex/arg.js delete mode 100644 src/docs/function/complex/conj.js delete mode 100644 src/docs/function/complex/im.js delete mode 100644 src/docs/function/complex/re.js delete mode 100644 src/docs/function/construction/boolean.js delete mode 100644 src/docs/function/construction/complex.js delete mode 100644 src/docs/function/construction/matrix.js delete mode 100644 src/docs/function/construction/number.js delete mode 100644 src/docs/function/construction/range.js delete mode 100644 src/docs/function/construction/string.js delete mode 100644 src/docs/function/construction/unit.js delete mode 100644 src/docs/function/matrix/concat.js delete mode 100644 src/docs/function/matrix/det.js delete mode 100644 src/docs/function/matrix/diag.js delete mode 100644 src/docs/function/matrix/eye.js delete mode 100644 src/docs/function/matrix/inv.js delete mode 100644 src/docs/function/matrix/ones.js delete mode 100644 src/docs/function/matrix/size.js delete mode 100644 src/docs/function/matrix/squeeze.js delete mode 100644 src/docs/function/matrix/subset.js delete mode 100644 src/docs/function/matrix/transpose.js delete mode 100644 src/docs/function/matrix/zeros.js delete mode 100644 src/docs/function/probability/factorial.js delete mode 100644 src/docs/function/probability/random.js delete mode 100644 src/docs/function/probability/randomInt.js delete mode 100644 src/docs/function/statistics/max.js delete mode 100644 src/docs/function/statistics/min.js delete mode 100644 src/docs/function/trigonometry/acos.js delete mode 100644 src/docs/function/trigonometry/asin.js delete mode 100644 src/docs/function/trigonometry/atan.js delete mode 100644 src/docs/function/trigonometry/atan2.js delete mode 100644 src/docs/function/trigonometry/cos.js delete mode 100644 src/docs/function/trigonometry/cot.js delete mode 100644 src/docs/function/trigonometry/csc.js delete mode 100644 src/docs/function/trigonometry/sec.js delete mode 100644 src/docs/function/trigonometry/sin.js delete mode 100644 src/docs/function/trigonometry/tan.js delete mode 100644 src/docs/function/units/in.js delete mode 100644 src/docs/function/utils/clone.js delete mode 100644 src/docs/function/utils/eval.js delete mode 100644 src/docs/function/utils/format.js delete mode 100644 src/docs/function/utils/help.js delete mode 100644 src/docs/function/utils/import.js delete mode 100644 src/docs/function/utils/typeof.js delete mode 100644 src/docs/index.js delete mode 100644 src/exports.js delete mode 100644 src/expr/Parser.js delete mode 100644 src/expr/Scope.js delete mode 100644 src/expr/Selector.js delete mode 100644 src/expr/node/AssignmentNode.js delete mode 100644 src/expr/node/BlockNode.js delete mode 100644 src/expr/node/ConstantNode.js delete mode 100644 src/expr/node/FunctionNode.js delete mode 100644 src/expr/node/MatrixNode.js delete mode 100644 src/expr/node/Node.js delete mode 100644 src/expr/node/OperatorNode.js delete mode 100644 src/expr/node/ParamsNode.js delete mode 100644 src/expr/node/SymbolNode.js delete mode 100644 src/expr/node/UpdateNode.js delete mode 100644 src/expr/node/handlers.js delete mode 100644 src/expr/node/index.js delete mode 100644 src/function/arithmetic/abs.js delete mode 100644 src/function/arithmetic/add.js delete mode 100644 src/function/arithmetic/ceil.js delete mode 100644 src/function/arithmetic/cube.js delete mode 100644 src/function/arithmetic/divide.js delete mode 100644 src/function/arithmetic/edivide.js delete mode 100644 src/function/arithmetic/emultiply.js delete mode 100644 src/function/arithmetic/epow.js delete mode 100644 src/function/arithmetic/equal.js delete mode 100644 src/function/arithmetic/exp.js delete mode 100644 src/function/arithmetic/fix.js delete mode 100644 src/function/arithmetic/floor.js delete mode 100644 src/function/arithmetic/gcd.js delete mode 100644 src/function/arithmetic/larger.js delete mode 100644 src/function/arithmetic/largereq.js delete mode 100644 src/function/arithmetic/lcm.js delete mode 100644 src/function/arithmetic/log.js delete mode 100644 src/function/arithmetic/log10.js delete mode 100644 src/function/arithmetic/mod.js delete mode 100644 src/function/arithmetic/multiply.js delete mode 100644 src/function/arithmetic/pow.js delete mode 100644 src/function/arithmetic/round.js delete mode 100644 src/function/arithmetic/sign.js delete mode 100644 src/function/arithmetic/smaller.js delete mode 100644 src/function/arithmetic/smallereq.js delete mode 100644 src/function/arithmetic/sqrt.js delete mode 100644 src/function/arithmetic/square.js delete mode 100644 src/function/arithmetic/subtract.js delete mode 100644 src/function/arithmetic/unary.js delete mode 100644 src/function/arithmetic/unequal.js delete mode 100644 src/function/arithmetic/xgcd.js delete mode 100644 src/function/complex/arg.js delete mode 100644 src/function/complex/conj.js delete mode 100644 src/function/complex/im.js delete mode 100644 src/function/complex/re.js delete mode 100644 src/function/construction/boolean.js delete mode 100644 src/function/construction/complex.js delete mode 100644 src/function/construction/matrix.js delete mode 100644 src/function/construction/number.js delete mode 100644 src/function/construction/parser.js delete mode 100644 src/function/construction/range.js delete mode 100644 src/function/construction/string.js delete mode 100644 src/function/construction/unit.js delete mode 100644 src/function/matrix/concat.js delete mode 100644 src/function/matrix/det.js delete mode 100644 src/function/matrix/diag.js delete mode 100644 src/function/matrix/eye.js delete mode 100644 src/function/matrix/inv.js delete mode 100644 src/function/matrix/ones.js delete mode 100644 src/function/matrix/size.js delete mode 100644 src/function/matrix/squeeze.js delete mode 100644 src/function/matrix/subset.js delete mode 100644 src/function/matrix/transpose.js delete mode 100644 src/function/matrix/zeros.js delete mode 100644 src/function/probability/factorial.js delete mode 100644 src/function/probability/random.js delete mode 100644 src/function/statistics/max.js delete mode 100644 src/function/statistics/min.js delete mode 100644 src/function/trigonometry/acos.js delete mode 100644 src/function/trigonometry/asin.js delete mode 100644 src/function/trigonometry/atan.js delete mode 100644 src/function/trigonometry/atan2.js delete mode 100644 src/function/trigonometry/cos.js delete mode 100644 src/function/trigonometry/cot.js delete mode 100644 src/function/trigonometry/csc.js delete mode 100644 src/function/trigonometry/sec.js delete mode 100644 src/function/trigonometry/sin.js delete mode 100644 src/function/trigonometry/tan.js delete mode 100644 src/function/units/in.js delete mode 100644 src/function/utils/clone.js delete mode 100644 src/function/utils/eval.js delete mode 100644 src/function/utils/format.js delete mode 100644 src/function/utils/help.js delete mode 100644 src/function/utils/import.js delete mode 100644 src/function/utils/parse.js delete mode 100644 src/function/utils/select.js delete mode 100644 src/function/utils/typeof.js delete mode 100644 src/header.js delete mode 100644 src/index.js delete mode 100644 src/options.js delete mode 100644 src/shim.js delete mode 100644 src/type/Complex.js delete mode 100644 src/type/Help.js delete mode 100644 src/type/Matrix.js delete mode 100644 src/type/Range.js delete mode 100644 src/type/Unit.js delete mode 100644 src/type/collection.js delete mode 100644 src/type/index.js delete mode 100644 src/util/array.js delete mode 100644 src/util/boolean.js delete mode 100644 src/util/error.js delete mode 100644 src/util/index.js delete mode 100644 src/util/number.js delete mode 100644 src/util/object.js delete mode 100644 src/util/string.js delete mode 100644 src/util/types.js diff --git a/.npmignore b/.npmignore index cbef13a0c..f40958eea 100644 --- a/.npmignore +++ b/.npmignore @@ -2,7 +2,6 @@ coverage img misc node_modules -src test tools component.json diff --git a/Jakefile.js b/Jakefile.js index c543f7a65..c301684a0 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -9,7 +9,7 @@ var jake = require('jake'), /** * Constants */ -var HEADER = './src/header.js'; +var HEADER = './lib/header.js'; var DIST = './dist'; var MATHJS = DIST + '/math.js'; var MATHJS_MIN = DIST + '/math.min.js'; @@ -38,7 +38,7 @@ task('bundle', {async: true}, function () { // make directory dist jake.mkdirP(DIST); - b.add('./src/index.js'); + b.add('./lib/index.js'); b.bundle({ standalone: 'math' }, function (err, code) { @@ -47,7 +47,7 @@ task('bundle', {async: true}, function () { } // add header and shim - var lib = util.read('./src/header.js') + code + util.read('./src/shim.js'); + var lib = util.read('./lib/header.js') + code + util.read('./lib/shim.js'); // write bundled file util.write(MATHJS, lib); diff --git a/README.md b/README.md index 4a1667518..d0ae94723 100644 --- a/README.md +++ b/README.md @@ -732,7 +732,7 @@ There are a few preferences regarding code contributions: - Math.js follows the node.js code style as described [here](http://nodeguide.com/style.html). - Send pull requests to the `develop` branch, not the `master` branch. -- Only commit changes done in the source files under `src`, not to the library +- Only commit changes done in the source files under `lib`, not to the builds, which are under `dist`. builds `math.js` and `math.min.js`. Thanks! diff --git a/bower.json b/bower.json index 3142b6ef3..6b2b1846d 100644 --- a/bower.json +++ b/bower.json @@ -7,7 +7,7 @@ "img", "misc", "node_modules", - "src", + "lib", "test", "tools", ".gitignore", diff --git a/index.js b/index.js index ae3f7bd9b..80af54e81 100644 --- a/index.js +++ b/index.js @@ -1 +1,116 @@ -module.exports = require('./src/index.js'); \ No newline at end of file +// options (global configuration settings) +exports.options = require('./lib/options'); + +// expression (Parser, Scope, Nodes) +exports.expr = {}; +exports.expr.node = require('./lib/expr/node/index.js'); +exports.expr.Scope = require('./lib/expr/Scope.js'); +exports.expr.Parser = require('./lib/expr/Parser.js'); + +// types (Matrix, Complex, Unit, ...) +exports.type = require('./lib/type/index.js'); + +// docs +exports.docs = require('./lib/docs/index.js'); + +// functions - arithmetic +require('./lib/function/arithmetic/abs.js')(exports); +require('./lib/function/arithmetic/add.js')(exports); +require('./lib/function/arithmetic/add.js')(exports); +require('./lib/function/arithmetic/ceil.js')(exports); +require('./lib/function/arithmetic/cube.js')(exports); +require('./lib/function/arithmetic/divide.js')(exports); +require('./lib/function/arithmetic/edivide.js')(exports); +require('./lib/function/arithmetic/emultiply.js')(exports); +require('./lib/function/arithmetic/epow.js')(exports); +require('./lib/function/arithmetic/equal.js')(exports); +require('./lib/function/arithmetic/exp.js')(exports); +require('./lib/function/arithmetic/fix.js')(exports); +require('./lib/function/arithmetic/floor.js')(exports); +require('./lib/function/arithmetic/gcd.js')(exports); +require('./lib/function/arithmetic/larger.js')(exports); +require('./lib/function/arithmetic/largereq.js')(exports); +require('./lib/function/arithmetic/lcm.js')(exports); +require('./lib/function/arithmetic/log.js')(exports); +require('./lib/function/arithmetic/log10.js')(exports); +require('./lib/function/arithmetic/mod.js')(exports); +require('./lib/function/arithmetic/multiply.js')(exports); +require('./lib/function/arithmetic/pow.js')(exports); +require('./lib/function/arithmetic/round.js')(exports); +require('./lib/function/arithmetic/sign.js')(exports); +require('./lib/function/arithmetic/smaller.js')(exports); +require('./lib/function/arithmetic/smallereq.js')(exports); +require('./lib/function/arithmetic/sqrt.js')(exports); +require('./lib/function/arithmetic/square.js')(exports); +require('./lib/function/arithmetic/subtract.js')(exports); +require('./lib/function/arithmetic/unary.js')(exports); +require('./lib/function/arithmetic/unequal.js')(exports); +require('./lib/function/arithmetic/xgcd.js')(exports); + +// functions - complex +require('./lib/function/complex/arg.js')(exports); +require('./lib/function/complex/conj.js')(exports); +require('./lib/function/complex/re.js')(exports); +require('./lib/function/complex/im.js')(exports); + +// functions - construction +require('./lib/function/construction/boolean.js')(exports); +require('./lib/function/construction/complex.js')(exports); +require('./lib/function/construction/matrix.js')(exports); +require('./lib/function/construction/number.js')(exports); +require('./lib/function/construction/parser.js')(exports); +require('./lib/function/construction/range.js')(exports); +require('./lib/function/construction/string.js')(exports); +require('./lib/function/construction/unit.js')(exports); + +// functions - matrix +require('./lib/function/matrix/concat.js')(exports); +require('./lib/function/matrix/det.js')(exports); +require('./lib/function/matrix/diag.js')(exports); +require('./lib/function/matrix/eye.js')(exports); +require('./lib/function/matrix/inv.js')(exports); +require('./lib/function/matrix/ones.js')(exports); +require('./lib/function/matrix/size.js')(exports); +require('./lib/function/matrix/squeeze.js')(exports); +require('./lib/function/matrix/subset.js')(exports); +require('./lib/function/matrix/transpose.js')(exports); +require('./lib/function/matrix/zeros.js')(exports); + +// functions - probability +require('./lib/function/probability/factorial.js')(exports); +require('./lib/function/probability/random.js')(exports); + +// functions - statistics +require('./lib/function/statistics/min.js')(exports); +require('./lib/function/statistics/max.js')(exports); + +// functions - trigonometry +require('./lib/function/trigonometry/acos.js')(exports); +require('./lib/function/trigonometry/asin.js')(exports); +require('./lib/function/trigonometry/atan.js')(exports); +require('./lib/function/trigonometry/atan2.js')(exports); +require('./lib/function/trigonometry/cos.js')(exports); +require('./lib/function/trigonometry/cot.js')(exports); +require('./lib/function/trigonometry/csc.js')(exports); +require('./lib/function/trigonometry/sec.js')(exports); +require('./lib/function/trigonometry/sin.js')(exports); +require('./lib/function/trigonometry/tan.js')(exports); + +// functions - units +require('./lib/function/units/in.js')(exports); + +// functions - utils +require('./lib/function/utils/clone.js')(exports); +require('./lib/function/utils/eval.js')(exports); +require('./lib/function/utils/format.js')(exports); +require('./lib/function/utils/help.js')(exports); +require('./lib/function/utils/import.js')(exports); +require('./lib/function/utils/parse.js')(exports); +require('./lib/function/utils/select.js')(exports); +require('./lib/function/utils/typeof.js')(exports); + +// constants +require('./lib/constants.js')(exports); + +// selector (we initialize after all functions are loaded) +exports.expr.Selector = require('./lib/expr/Selector.js')(exports); diff --git a/package.json b/package.json index 13207e0c4..269a5fcdf 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,6 @@ "scripts": { "test": "mocha test --recursive --reporter spec" }, - "main": "./dist/math.js", "bin": { "mathjs": "./bin/cli.js" }, diff --git a/src/constants.js b/src/constants.js deleted file mode 100644 index 21f77137a..000000000 --- a/src/constants.js +++ /dev/null @@ -1,23 +0,0 @@ -module.exports = function (math) { - var Complex = require('./type/Complex.js'); - - math.pi = Math.PI; - math.e = Math.E; - math.tau = Math.PI * 2; - math.i = new Complex(0, 1); - - math['Infinity'] = Infinity; - math['NaN'] = NaN; - math['true'] = true; - math['false'] = false; - - // uppercase constants (for compatibility with built-in Math) - math.E = Math.E; - math.LN2 = Math.LN2; - math.LN10 = Math.LN10; - math.LOG2E = Math.LOG2E; - math.LOG10E = Math.LOG10E; - math.PI = Math.PI; - math.SQRT1_2 = Math.SQRT1_2; - math.SQRT2 = Math.SQRT2; -}; diff --git a/src/docs/constants/Infinity.js b/src/docs/constants/Infinity.js deleted file mode 100644 index 181ae1693..000000000 --- a/src/docs/constants/Infinity.js +++ /dev/null @@ -1,13 +0,0 @@ -module.exports = { - 'name': 'Infinity', - 'category': 'Constants', - 'syntax': [ - 'Infinity' - ], - 'description': 'Infinity, a number which is larger than the maximum number that can be handled by a floating point number.', - 'examples': [ - 'Infinity', - '1 / 0' - ], - 'seealso': [] -}; diff --git a/src/docs/constants/LN10.js b/src/docs/constants/LN10.js deleted file mode 100644 index f9bad91a0..000000000 --- a/src/docs/constants/LN10.js +++ /dev/null @@ -1,13 +0,0 @@ -module.exports = { - 'name': 'LN10', - 'category': 'Constants', - 'syntax': [ - 'LN10' - ], - 'description': 'Returns the natural logarithm of 10, approximately equal to 2.302', - 'examples': [ - 'LN10', - 'log(10)' - ], - 'seealso': [] -}; diff --git a/src/docs/constants/LN2.js b/src/docs/constants/LN2.js deleted file mode 100644 index fad9b55c2..000000000 --- a/src/docs/constants/LN2.js +++ /dev/null @@ -1,13 +0,0 @@ -module.exports = { - 'name': 'LN2', - 'category': 'Constants', - 'syntax': [ - 'LN2' - ], - 'description': 'Returns the natural logarithm of 2, approximately equal to 0.693', - 'examples': [ - 'LN2', - 'log(2)' - ], - 'seealso': [] -}; diff --git a/src/docs/constants/LOG10E.js b/src/docs/constants/LOG10E.js deleted file mode 100644 index 2b8c7da2c..000000000 --- a/src/docs/constants/LOG10E.js +++ /dev/null @@ -1,13 +0,0 @@ -module.exports = { - 'name': 'LOG10E', - 'category': 'Constants', - 'syntax': [ - 'LOG10E' - ], - 'description': 'Returns the base-10 logarithm of E, approximately equal to 0.434', - 'examples': [ - 'LOG10E', - 'log(e, 10)' - ], - 'seealso': [] -}; diff --git a/src/docs/constants/LOG2E.js b/src/docs/constants/LOG2E.js deleted file mode 100644 index ebd1fa1b1..000000000 --- a/src/docs/constants/LOG2E.js +++ /dev/null @@ -1,13 +0,0 @@ -module.exports = { - 'name': 'LOG2E', - 'category': 'Constants', - 'syntax': [ - 'LOG2E' - ], - 'description': 'Returns the base-2 logarithm of E, approximately equal to 1.442', - 'examples': [ - 'LOG2E', - 'log(e, 2)' - ], - 'seealso': [] -}; diff --git a/src/docs/constants/NaN.js b/src/docs/constants/NaN.js deleted file mode 100644 index afcf76a2d..000000000 --- a/src/docs/constants/NaN.js +++ /dev/null @@ -1,13 +0,0 @@ -module.exports = { - 'name': 'NaN', - 'category': 'Constants', - 'syntax': [ - 'NaN' - ], - 'description': 'Not a number', - 'examples': [ - 'NaN', - '0 / 0' - ], - 'seealso': [] -}; diff --git a/src/docs/constants/SQRT1_2.js b/src/docs/constants/SQRT1_2.js deleted file mode 100644 index 0ed86aaef..000000000 --- a/src/docs/constants/SQRT1_2.js +++ /dev/null @@ -1,13 +0,0 @@ -module.exports = { - 'name': 'SQRT1_2', - 'category': 'Constants', - 'syntax': [ - 'SQRT1_2' - ], - 'description': 'Returns the square root of 1/2, approximately equal to 0.707', - 'examples': [ - 'SQRT1_2', - 'sqrt(1/2)' - ], - 'seealso': [] -}; diff --git a/src/docs/constants/SQRT2.js b/src/docs/constants/SQRT2.js deleted file mode 100644 index d89d4c3c4..000000000 --- a/src/docs/constants/SQRT2.js +++ /dev/null @@ -1,13 +0,0 @@ -module.exports = { - 'name': 'SQRT2', - 'category': 'Constants', - 'syntax': [ - 'SQRT2' - ], - 'description': 'Returns the square root of 2, approximately equal to 1.414', - 'examples': [ - 'SQRT2', - 'sqrt(2)' - ], - 'seealso': [] -}; diff --git a/src/docs/constants/e.js b/src/docs/constants/e.js deleted file mode 100644 index c12df5319..000000000 --- a/src/docs/constants/e.js +++ /dev/null @@ -1,15 +0,0 @@ -module.exports = { - 'name': 'e', - 'category': 'Constants', - 'syntax': [ - 'e' - ], - 'description': 'Euler\'s number, the base of the natural logarithm. Approximately equal to 2.71828', - 'examples': [ - 'e', - 'e ^ 2', - 'exp(2)', - 'log(e)' - ], - 'seealso': ['exp'] -}; diff --git a/src/docs/constants/false.js b/src/docs/constants/false.js deleted file mode 100644 index 851084e6e..000000000 --- a/src/docs/constants/false.js +++ /dev/null @@ -1,12 +0,0 @@ -module.exports = { - 'name': 'false', - 'category': 'Constants', - 'syntax': [ - 'false' - ], - 'description': 'Boolean value false', - 'examples': [ - 'false' - ], - 'seealso': ['true'] -}; diff --git a/src/docs/constants/i.js b/src/docs/constants/i.js deleted file mode 100644 index ae340203a..000000000 --- a/src/docs/constants/i.js +++ /dev/null @@ -1,14 +0,0 @@ -module.exports = { - 'name': 'i', - 'category': 'Constants', - 'syntax': [ - 'i' - ], - 'description': 'Imaginary unit, defined as i*i=-1. A complex number is described as a + b*i, where a is the real part, and b is the imaginary part.', - 'examples': [ - 'i', - 'i * i', - 'sqrt(-1)' - ], - 'seealso': [] -}; diff --git a/src/docs/constants/pi.js b/src/docs/constants/pi.js deleted file mode 100644 index ed7ea151d..000000000 --- a/src/docs/constants/pi.js +++ /dev/null @@ -1,13 +0,0 @@ -module.exports = { - 'name': 'pi', - 'category': 'Constants', - 'syntax': [ - 'pi' - ], - 'description': 'The number pi is a mathematical constant that is the ratio of a circle\'s circumference to its diameter, and is approximately equal to 3.14159', - 'examples': [ - 'pi', - 'sin(pi/2)' - ], - 'seealso': ['tau'] -}; diff --git a/src/docs/constants/tau.js b/src/docs/constants/tau.js deleted file mode 100644 index 76e3f254b..000000000 --- a/src/docs/constants/tau.js +++ /dev/null @@ -1,13 +0,0 @@ -module.exports = { - 'name': 'tau', - 'category': 'Constants', - 'syntax': [ - 'pi' - ], - 'description': 'Tau is the ratio constant of a circle\'s circumference to radius, equal to 2 * pi, approximately 6.2832.', - 'examples': [ - 'tau', - '2 * pi' - ], - 'seealso': ['pi'] -}; diff --git a/src/docs/constants/true.js b/src/docs/constants/true.js deleted file mode 100644 index fce262c3a..000000000 --- a/src/docs/constants/true.js +++ /dev/null @@ -1,12 +0,0 @@ -module.exports = { - 'name': 'true', - 'category': 'Constants', - 'syntax': [ - 'true' - ], - 'description': 'Boolean value true', - 'examples': [ - 'true' - ], - 'seealso': ['false'] -}; diff --git a/src/docs/function/arithmetic/abs.js b/src/docs/function/arithmetic/abs.js deleted file mode 100644 index 4b5bf329b..000000000 --- a/src/docs/function/arithmetic/abs.js +++ /dev/null @@ -1,13 +0,0 @@ -module.exports = { - 'name': 'abs', - 'category': 'Arithmetic', - 'syntax': [ - 'abs(x)' - ], - 'description': 'Compute the absolute value.', - 'examples': [ - 'abs(3.5)', - 'abs(-4.2)' - ], - 'seealso': ['sign'] -}; diff --git a/src/docs/function/arithmetic/add.js b/src/docs/function/arithmetic/add.js deleted file mode 100644 index 0c4193c55..000000000 --- a/src/docs/function/arithmetic/add.js +++ /dev/null @@ -1,19 +0,0 @@ -module.exports = { - 'name': 'add', - 'category': 'Operators', - 'syntax': [ - 'x + y', - 'add(x, y)' - ], - 'description': 'Add two values.', - 'examples': [ - '2.1 + 3.6', - 'ans - 3.6', - '3 + 2i', - '"hello" + " world"', - '3 cm + 2 inch' - ], - 'seealso': [ - 'subtract' - ] -}; diff --git a/src/docs/function/arithmetic/ceil.js b/src/docs/function/arithmetic/ceil.js deleted file mode 100644 index 1395437a0..000000000 --- a/src/docs/function/arithmetic/ceil.js +++ /dev/null @@ -1,15 +0,0 @@ -module.exports = { - 'name': 'ceil', - 'category': 'Arithmetic', - 'syntax': [ - 'ceil(x)' - ], - 'description': - 'Round a value towards plus infinity.If x is complex, both real and imaginary part are rounded towards plus infinity.', - 'examples': [ - 'ceil(3.2)', - 'ceil(3.8)', - 'ceil(-4.2)' - ], - 'seealso': ['floor', 'fix', 'round'] -}; diff --git a/src/docs/function/arithmetic/cube.js b/src/docs/function/arithmetic/cube.js deleted file mode 100644 index 21c586678..000000000 --- a/src/docs/function/arithmetic/cube.js +++ /dev/null @@ -1,18 +0,0 @@ -module.exports = { - 'name': 'cube', - 'category': 'Arithmetic', - 'syntax': [ - 'cube(x)' - ], - 'description': 'Compute the cube of a value. The cube of x is x * x * x.', - 'examples': [ - 'cube(2)', - '2^3', - '2 * 2 * 2' - ], - 'seealso': [ - 'multiply', - 'square', - 'pow' - ] -}; diff --git a/src/docs/function/arithmetic/divide.js b/src/docs/function/arithmetic/divide.js deleted file mode 100644 index fbc51a9f6..000000000 --- a/src/docs/function/arithmetic/divide.js +++ /dev/null @@ -1,20 +0,0 @@ -module.exports = { - 'name': 'divide', - 'category': 'Operators', - 'syntax': [ - 'x / y', - 'divide(x, y)' - ], - 'description': 'Divide two values.', - 'examples': [ - '2 / 3', - 'ans * 3', - '4.5 / 2', - '3 + 4 / 2', - '(3 + 4) / 2', - '18 km / 4.5' - ], - 'seealso': [ - 'multiply' - ] -}; diff --git a/src/docs/function/arithmetic/edivide.js b/src/docs/function/arithmetic/edivide.js deleted file mode 100644 index 40c503d8d..000000000 --- a/src/docs/function/arithmetic/edivide.js +++ /dev/null @@ -1,19 +0,0 @@ -module.exports = { - 'name': 'edivide', - 'category': 'Operators', - 'syntax': [ - 'x ./ y', - 'edivide(x, y)' - ], - 'description': 'divide two values element wise.', - 'examples': [ - 'a = [1, 2, 3; 4, 5, 6]', - 'b = [2, 1, 1; 3, 2, 5]', - 'a ./ b' - ], - 'seealso': [ - 'multiply', - 'emultiply', - 'divide' - ] -}; diff --git a/src/docs/function/arithmetic/emultiply.js b/src/docs/function/arithmetic/emultiply.js deleted file mode 100644 index 909026da0..000000000 --- a/src/docs/function/arithmetic/emultiply.js +++ /dev/null @@ -1,19 +0,0 @@ -module.exports = { - 'name': 'emultiply', - 'category': 'Operators', - 'syntax': [ - 'x .* y', - 'emultiply(x, y)' - ], - 'description': 'multiply two values element wise.', - 'examples': [ - 'a = [1, 2, 3; 4, 5, 6]', - 'b = [2, 1, 1; 3, 2, 5]', - 'a .* b' - ], - 'seealso': [ - 'multiply', - 'divide', - 'edivide' - ] -}; diff --git a/src/docs/function/arithmetic/epow.js b/src/docs/function/arithmetic/epow.js deleted file mode 100644 index 367c0f11d..000000000 --- a/src/docs/function/arithmetic/epow.js +++ /dev/null @@ -1,17 +0,0 @@ -module.exports = { - 'name': 'epow', - 'category': 'Operators', - 'syntax': [ - 'x .^ y', - 'epow(x, y)' - ], - 'description': - 'Calculates the power of x to y element wise.', - 'examples': [ - 'a = [1, 2, 3; 4, 5, 6]', - 'a .^ 2' - ], - 'seealso': [ - 'pow' - ] -}; diff --git a/src/docs/function/arithmetic/equal.js b/src/docs/function/arithmetic/equal.js deleted file mode 100644 index e1b1eca27..000000000 --- a/src/docs/function/arithmetic/equal.js +++ /dev/null @@ -1,21 +0,0 @@ -module.exports = { - 'name': 'equal', - 'category': 'Operators', - 'syntax': [ - 'x == y', - 'equal(x, y)' - ], - 'description': - 'Check equality of two values. Returns 1 if the values are equal, and 0 if not.', - 'examples': [ - '2+2 == 3', - '2+2 == 4', - 'a = 3.2', - 'b = 6-2.8', - 'a == b', - '50cm == 0.5m' - ], - 'seealso': [ - 'unequal', 'smaller', 'larger', 'smallereq', 'largereq' - ] -}; diff --git a/src/docs/function/arithmetic/exp.js b/src/docs/function/arithmetic/exp.js deleted file mode 100644 index e3afaafb1..000000000 --- a/src/docs/function/arithmetic/exp.js +++ /dev/null @@ -1,20 +0,0 @@ -module.exports = { - 'name': 'exp', - 'category': 'Arithmetic', - 'syntax': [ - 'exp(x)' - ], - 'description': 'Calculate the exponent of a value.', - 'examples': [ - 'exp(1.3)', - 'e ^ 1.3', - 'log(exp(1.3))', - 'x = 2.4', - '(exp(i*x) == cos(x) + i*sin(x)) # Euler\'s formula' - ], - 'seealso': [ - 'square', - 'multiply', - 'log' - ] -}; diff --git a/src/docs/function/arithmetic/fix.js b/src/docs/function/arithmetic/fix.js deleted file mode 100644 index 94f6b762a..000000000 --- a/src/docs/function/arithmetic/fix.js +++ /dev/null @@ -1,16 +0,0 @@ -module.exports = { - 'name': 'fix', - 'category': 'Arithmetic', - 'syntax': [ - 'fix(x)' - ], - 'description': - 'Round a value towards zero.If x is complex, both real and imaginary part are rounded towards zero.', - 'examples': [ - 'fix(3.2)', - 'fix(3.8)', - 'fix(-4.2)', - 'fix(-4.8)' - ], - 'seealso': ['ceil', 'floor', 'round'] -}; diff --git a/src/docs/function/arithmetic/floor.js b/src/docs/function/arithmetic/floor.js deleted file mode 100644 index 2075fd3ee..000000000 --- a/src/docs/function/arithmetic/floor.js +++ /dev/null @@ -1,15 +0,0 @@ -module.exports = { - 'name': 'floor', - 'category': 'Arithmetic', - 'syntax': [ - 'floor(x)' - ], - 'description': - 'Round a value towards minus infinity.If x is complex, both real and imaginary part are rounded towards minus infinity.', - 'examples': [ - 'floor(3.2)', - 'floor(3.8)', - 'floor(-4.2)' - ], - 'seealso': ['ceil', 'fix', 'round'] -}; diff --git a/src/docs/function/arithmetic/gcd.js b/src/docs/function/arithmetic/gcd.js deleted file mode 100644 index 160ceb138..000000000 --- a/src/docs/function/arithmetic/gcd.js +++ /dev/null @@ -1,15 +0,0 @@ -module.exports = { - 'name': 'gcd', - 'category': 'Arithmetic', - 'syntax': [ - 'gcd(a, b)', - 'gcd(a, b, c, ...)' - ], - 'description': 'Compute the greatest common divisor.', - 'examples': [ - 'gcd(8, 12)', - 'gcd(-4, 6)', - 'gcd(25, 15, -10)' - ], - 'seealso': [ 'lcm', 'xgcd' ] -}; diff --git a/src/docs/function/arithmetic/larger.js b/src/docs/function/arithmetic/larger.js deleted file mode 100644 index c7506d4f9..000000000 --- a/src/docs/function/arithmetic/larger.js +++ /dev/null @@ -1,22 +0,0 @@ -module.exports = { - 'name': 'larger', - 'category': 'Operators', - 'syntax': [ - 'x > y', - 'larger(x, y)' - ], - 'description': - 'Check if value x is larger than y. Returns 1 if x is larger than y, and 0 if not.', - 'examples': [ - '2 > 3', - '5 > 2*2', - 'a = 3.3', - 'b = 6-2.8', - '(a > b)', - '(b < a)', - '5 cm > 2 inch' - ], - 'seealso': [ - 'equal', 'unequal', 'smaller', 'smallereq', 'largereq' - ] -}; diff --git a/src/docs/function/arithmetic/largereq.js b/src/docs/function/arithmetic/largereq.js deleted file mode 100644 index 3f6725b16..000000000 --- a/src/docs/function/arithmetic/largereq.js +++ /dev/null @@ -1,20 +0,0 @@ -module.exports = { - 'name': 'largereq', - 'category': 'Operators', - 'syntax': [ - 'x >= y', - 'largereq(x, y)' - ], - 'description': - 'Check if value x is larger or equal to y. Returns 1 if x is larger or equal to y, and 0 if not.', - 'examples': [ - '2 > 1+1', - '2 >= 1+1', - 'a = 3.2', - 'b = 6-2.8', - '(a > b)' - ], - 'seealso': [ - 'equal', 'unequal', 'smallereq', 'smaller', 'largereq' - ] -}; diff --git a/src/docs/function/arithmetic/lcm.js b/src/docs/function/arithmetic/lcm.js deleted file mode 100644 index c06bb0da5..000000000 --- a/src/docs/function/arithmetic/lcm.js +++ /dev/null @@ -1,14 +0,0 @@ -module.exports = { - 'name': 'lcm', - 'category': 'Arithmetic', - 'syntax': [ - 'lcm(x, y)' - ], - 'description': 'Compute the least common multiple.', - 'examples': [ - 'lcm(4, 6)', - 'lcm(6, 21)', - 'lcm(6, 21, 5)' - ], - 'seealso': [ 'gcd' ] -}; diff --git a/src/docs/function/arithmetic/log.js b/src/docs/function/arithmetic/log.js deleted file mode 100644 index 1117d63fa..000000000 --- a/src/docs/function/arithmetic/log.js +++ /dev/null @@ -1,23 +0,0 @@ -module.exports = { - 'name': 'log', - 'category': 'Arithmetic', - 'syntax': [ - 'log(x)', - 'log(x, base)' - ], - 'description': 'Compute the logarithm of a value. If no base is provided, the natural logarithm of x is calculated. If base if provided, the logarithm is calculated for the specified base. log(x, base) is defined as log(x) / log(base).', - 'examples': [ - 'log(3.5)', - 'a = log(2.4)', - 'exp(a)', - '10 ^ 3', - 'log(1000, 10)', - 'log(1000) / log(10)', - 'b = logb(1024, 2)', - '2 ^ b' - ], - 'seealso': [ - 'exp', - 'log10' - ] -}; \ No newline at end of file diff --git a/src/docs/function/arithmetic/log10.js b/src/docs/function/arithmetic/log10.js deleted file mode 100644 index 4c1035875..000000000 --- a/src/docs/function/arithmetic/log10.js +++ /dev/null @@ -1,19 +0,0 @@ -module.exports = { - 'name': 'log10', - 'category': 'Arithmetic', - 'syntax': [ - 'log10(x)' - ], - 'description': 'Compute the 10-base logarithm of a value.', - 'examples': [ - 'log10(1000)', - '10 ^ 3', - 'log10(0.01)', - 'log(1000) / log(10)', - 'log(1000, 10)' - ], - 'seealso': [ - 'exp', - 'log' - ] -}; diff --git a/src/docs/function/arithmetic/mod.js b/src/docs/function/arithmetic/mod.js deleted file mode 100644 index 8b96d915f..000000000 --- a/src/docs/function/arithmetic/mod.js +++ /dev/null @@ -1,20 +0,0 @@ -module.exports = { - 'name': 'mod', - 'category': 'Operators', - 'syntax': [ - 'x % y', - 'x mod y', - 'mod(x, y)' - ], - 'description': - 'Calculates the modulus, the remainder of an integer division.', - 'examples': [ - '7 % 3', - '11 % 2', - '10 mod 4', - 'function isOdd(x) = x % 2', - 'isOdd(2)', - 'isOdd(3)' - ], - 'seealso': [] -}; diff --git a/src/docs/function/arithmetic/multiply.js b/src/docs/function/arithmetic/multiply.js deleted file mode 100644 index c808d35e6..000000000 --- a/src/docs/function/arithmetic/multiply.js +++ /dev/null @@ -1,19 +0,0 @@ -module.exports = { - 'name': 'multiply', - 'category': 'Operators', - 'syntax': [ - 'x * y', - 'multiply(x, y)' - ], - 'description': 'multiply two values.', - 'examples': [ - '2.1 * 3.6', - 'ans / 3.6', - '2 * 3 + 4', - '2 * (3 + 4)', - '3 * 2.1 km' - ], - 'seealso': [ - 'divide' - ] -}; diff --git a/src/docs/function/arithmetic/pow.js b/src/docs/function/arithmetic/pow.js deleted file mode 100644 index 87fda66b7..000000000 --- a/src/docs/function/arithmetic/pow.js +++ /dev/null @@ -1,18 +0,0 @@ -module.exports = { - 'name': 'pow', - 'category': 'Operators', - 'syntax': [ - 'x ^ y', - 'pow(x, y)' - ], - 'description': - 'Calculates the power of x to y, x^y.', - 'examples': [ - '2^3 = 8', - '2*2*2', - '1 + e ^ (pi * i)' - ], - 'seealso': [ - 'unequal', 'smaller', 'larger', 'smallereq', 'largereq' - ] -}; diff --git a/src/docs/function/arithmetic/round.js b/src/docs/function/arithmetic/round.js deleted file mode 100644 index 8dd193f0b..000000000 --- a/src/docs/function/arithmetic/round.js +++ /dev/null @@ -1,19 +0,0 @@ -module.exports = { - 'name': 'round', - 'category': 'Arithmetic', - 'syntax': [ - 'round(x)', - 'round(x, n)' - ], - 'description': - 'round a value towards the nearest integer.If x is complex, both real and imaginary part are rounded towards the nearest integer. When n is specified, the value is rounded to n decimals.', - 'examples': [ - 'round(3.2)', - 'round(3.8)', - 'round(-4.2)', - 'round(-4.8)', - 'round(pi, 3)', - 'round(123.45678, 2)' - ], - 'seealso': ['ceil', 'floor', 'fix'] -}; diff --git a/src/docs/function/arithmetic/sign.js b/src/docs/function/arithmetic/sign.js deleted file mode 100644 index 432196951..000000000 --- a/src/docs/function/arithmetic/sign.js +++ /dev/null @@ -1,17 +0,0 @@ -module.exports = { - 'name': 'sign', - 'category': 'Arithmetic', - 'syntax': [ - 'sign(x)' - ], - 'description': - 'Compute the sign of a value. The sign of a value x is 1 when x>1, -1 when x<0, and 0 when x=0.', - 'examples': [ - 'sign(3.5)', - 'sign(-4.2)', - 'sign(0)' - ], - 'seealso': [ - 'abs' - ] -}; diff --git a/src/docs/function/arithmetic/smaller.js b/src/docs/function/arithmetic/smaller.js deleted file mode 100644 index e6f7118de..000000000 --- a/src/docs/function/arithmetic/smaller.js +++ /dev/null @@ -1,21 +0,0 @@ -module.exports = { - 'name': 'smaller', - 'category': 'Operators', - 'syntax': [ - 'x < y', - 'smaller(x, y)' - ], - 'description': - 'Check if value x is smaller than value y. Returns 1 if x is smaller than y, and 0 if not.', - 'examples': [ - '2 < 3', - '5 < 2*2', - 'a = 3.3', - 'b = 6-2.8', - '(a < b)', - '5 cm < 2 inch' - ], - 'seealso': [ - 'equal', 'unequal', 'larger', 'smallereq', 'largereq' - ] -}; diff --git a/src/docs/function/arithmetic/smallereq.js b/src/docs/function/arithmetic/smallereq.js deleted file mode 100644 index f52a1f5be..000000000 --- a/src/docs/function/arithmetic/smallereq.js +++ /dev/null @@ -1,20 +0,0 @@ -module.exports = { - 'name': 'smallereq', - 'category': 'Operators', - 'syntax': [ - 'x <= y', - 'smallereq(x, y)' - ], - 'description': - 'Check if value x is smaller or equal to value y. Returns 1 if x is smaller than y, and 0 if not.', - 'examples': [ - '2 < 1+1', - '2 <= 1+1', - 'a = 3.2', - 'b = 6-2.8', - '(a < b)' - ], - 'seealso': [ - 'equal', 'unequal', 'larger', 'smaller', 'largereq' - ] -}; diff --git a/src/docs/function/arithmetic/sqrt.js b/src/docs/function/arithmetic/sqrt.js deleted file mode 100644 index d2d6d1cea..000000000 --- a/src/docs/function/arithmetic/sqrt.js +++ /dev/null @@ -1,18 +0,0 @@ -module.exports = { - 'name': 'sqrt', - 'category': 'Arithmetic', - 'syntax': [ - 'sqrt(x)' - ], - 'description': - 'Compute the square root value. If x = y * y, then y is the square root of x.', - 'examples': [ - 'sqrt(25)', - '5 * 5', - 'sqrt(-1)' - ], - 'seealso': [ - 'square', - 'multiply' - ] -}; diff --git a/src/docs/function/arithmetic/square.js b/src/docs/function/arithmetic/square.js deleted file mode 100644 index 99ccae2fc..000000000 --- a/src/docs/function/arithmetic/square.js +++ /dev/null @@ -1,21 +0,0 @@ -module.exports = { - 'name': 'square', - 'category': 'Arithmetic', - 'syntax': [ - 'square(x)' - ], - 'description': - 'Compute the square of a value. The square of x is x * x.', - 'examples': [ - 'square(3)', - 'sqrt(9)', - '3^2', - '3 * 3' - ], - 'seealso': [ - 'multiply', - 'pow', - 'sqrt', - 'cube' - ] -}; diff --git a/src/docs/function/arithmetic/subtract.js b/src/docs/function/arithmetic/subtract.js deleted file mode 100644 index 2ffefba6b..000000000 --- a/src/docs/function/arithmetic/subtract.js +++ /dev/null @@ -1,19 +0,0 @@ -module.exports = { - 'name': 'subtract', - 'category': 'Operators', - 'syntax': [ - 'x - y', - 'subtract(x, y)' - ], - 'description': 'subtract two values.', - 'examples': [ - '5.3 - 2', - 'ans + 2', - '2/3 - 1/6', - '2 * 3 - 3', - '2.1 km - 500m' - ], - 'seealso': [ - 'add' - ] -}; diff --git a/src/docs/function/arithmetic/unary.js b/src/docs/function/arithmetic/unary.js deleted file mode 100644 index 964b3acb6..000000000 --- a/src/docs/function/arithmetic/unary.js +++ /dev/null @@ -1,17 +0,0 @@ -module.exports = { - 'name': 'unary', - 'category': 'Operators', - 'syntax': [ - '-x', - 'unary(x)' - ], - 'description': - 'Inverse the sign of a value.', - 'examples': [ - '-4.5', - '-(-5.6)' - ], - 'seealso': [ - 'add', 'subtract' - ] -}; diff --git a/src/docs/function/arithmetic/unequal.js b/src/docs/function/arithmetic/unequal.js deleted file mode 100644 index 2311c5aa6..000000000 --- a/src/docs/function/arithmetic/unequal.js +++ /dev/null @@ -1,22 +0,0 @@ -module.exports = { - 'name': 'unequal', - 'category': 'Operators', - 'syntax': [ - 'x != y', - 'unequal(x, y)' - ], - 'description': - 'Check unequality of two values. Returns 1 if the values are unequal, and 0 if they are equal.', - 'examples': [ - '2+2 != 3', - '2+2 != 4', - 'a = 3.2', - 'b = 6-2.8', - 'a != b', - '50cm != 0.5m', - '5 cm != 2 inch' - ], - 'seealso': [ - 'equal', 'smaller', 'larger', 'smallereq', 'largereq' - ] -}; diff --git a/src/docs/function/arithmetic/xgcd.js b/src/docs/function/arithmetic/xgcd.js deleted file mode 100644 index c7232ac22..000000000 --- a/src/docs/function/arithmetic/xgcd.js +++ /dev/null @@ -1,14 +0,0 @@ -module.exports = { - 'name': 'xgcd', - 'category': 'Arithmetic', - 'syntax': [ - 'xgcd(a, b)' - ], - 'description': 'Calculate the extended greatest common divisor for two values', - 'examples': [ - 'xgcd(8, 12)', - 'gcd(8, 12)', - 'xgcd(36163, 21199)' - ], - 'seealso': [ 'gcd', 'lcm' ] -}; diff --git a/src/docs/function/complex/arg.js b/src/docs/function/complex/arg.js deleted file mode 100644 index 6f14b1fb8..000000000 --- a/src/docs/function/complex/arg.js +++ /dev/null @@ -1,20 +0,0 @@ -module.exports = { - 'name': 'arg', - 'category': 'Complex', - 'syntax': [ - 'arg(x)' - ], - 'description': - 'Compute the argument of a complex value. If x = a+bi, the argument is computed as atan2(b, a).', - 'examples': [ - 'arg(2 + 2i)', - 'atan2(3, 2)', - 'arg(2 - 3i)' - ], - 'seealso': [ - 're', - 'im', - 'conj', - 'abs' - ] -}; diff --git a/src/docs/function/complex/conj.js b/src/docs/function/complex/conj.js deleted file mode 100644 index b57b9813d..000000000 --- a/src/docs/function/complex/conj.js +++ /dev/null @@ -1,20 +0,0 @@ -module.exports = { - 'name': 'conj', - 'category': 'Complex', - 'syntax': [ - 'conj(x)' - ], - 'description': - 'Compute the complex conjugate of a complex value. If x = a+bi, the complex conjugate is a-bi.', - 'examples': [ - 'conj(2 + 3i)', - 'conj(2 - 3i)', - 'conj(-5.2i)' - ], - 'seealso': [ - 're', - 'im', - 'abs', - 'arg' - ] -}; diff --git a/src/docs/function/complex/im.js b/src/docs/function/complex/im.js deleted file mode 100644 index 7608d6575..000000000 --- a/src/docs/function/complex/im.js +++ /dev/null @@ -1,20 +0,0 @@ -module.exports = { - 'name': 'im', - 'category': 'Complex', - 'syntax': [ - 'im(x)' - ], - 'description': 'Get the imaginary part of a complex number.', - 'examples': [ - 'im(2 + 3i)', - 're(2 + 3i)', - 'im(-5.2i)', - 'im(2.4)' - ], - 'seealso': [ - 're', - 'conj', - 'abs', - 'arg' - ] -}; diff --git a/src/docs/function/complex/re.js b/src/docs/function/complex/re.js deleted file mode 100644 index 6fa53efeb..000000000 --- a/src/docs/function/complex/re.js +++ /dev/null @@ -1,20 +0,0 @@ -module.exports = { - 'name': 're', - 'category': 'Complex', - 'syntax': [ - 're(x)' - ], - 'description': 'Get the real part of a complex number.', - 'examples': [ - 're(2 + 3i)', - 'im(2 + 3i)', - 're(-5.2i)', - 're(2.4)' - ], - 'seealso': [ - 'im', - 'conj', - 'abs', - 'arg' - ] -}; diff --git a/src/docs/function/construction/boolean.js b/src/docs/function/construction/boolean.js deleted file mode 100644 index 5d830a2b0..000000000 --- a/src/docs/function/construction/boolean.js +++ /dev/null @@ -1,20 +0,0 @@ -module.exports = { - 'name': 'boolean', - 'category': 'Type', - 'syntax': [ - 'x', - 'boolean(x)' - ], - 'description': - 'Convert a string or number into a boolean.', - 'examples': [ - 'boolean(0)', - 'boolean(1)', - 'boolean(3)', - 'boolean("true")', - 'boolean("false")' - ], - 'seealso': [ - 'complex', 'matrix', 'range', 'string', 'unit' - ] -}; diff --git a/src/docs/function/construction/complex.js b/src/docs/function/construction/complex.js deleted file mode 100644 index 76882d6f9..000000000 --- a/src/docs/function/construction/complex.js +++ /dev/null @@ -1,19 +0,0 @@ -module.exports = { - 'name': 'complex', - 'category': 'Type', - 'syntax': [ - 'complex()', - 'complex(re, im)', - 'complex(string)' - ], - 'description': - 'Create a complex number.', - 'examples': [ - 'complex()', - 'complex(2, 3)', - 'complex("7 - 2i")' - ], - 'seealso': [ - 'boolean', 'matrix', 'number', 'range', 'string', 'unit' - ] -}; diff --git a/src/docs/function/construction/matrix.js b/src/docs/function/construction/matrix.js deleted file mode 100644 index 513b11e9e..000000000 --- a/src/docs/function/construction/matrix.js +++ /dev/null @@ -1,22 +0,0 @@ -module.exports = { - 'name': 'matrix', - 'category': 'Type', - 'syntax': [ - '[]', - '[a1, b1, ...; a2, b2, ...]', - 'matrix()', - 'matrix([...])' - ], - 'description': - 'Create a matrix.', - 'examples': [ - '[]', - '[1, 2, 3]', - '[1, 2, 3; 4, 5, 6]', - 'matrix()', - 'matrix([3, 4])' - ], - 'seealso': [ - 'boolean', 'complex', 'number', 'range', 'string', 'unit' - ] -}; diff --git a/src/docs/function/construction/number.js b/src/docs/function/construction/number.js deleted file mode 100644 index 72cf9a97a..000000000 --- a/src/docs/function/construction/number.js +++ /dev/null @@ -1,21 +0,0 @@ -module.exports = { - 'name': 'number', - 'category': 'Type', - 'syntax': [ - 'x', - 'number(x)' - ], - 'description': - 'Create a number or convert a string or boolean into a number.', - 'examples': [ - '2', - '2e3', - '4.05', - 'number(2)', - 'number("7.2")', - 'number(true)' - ], - 'seealso': [ - 'boolean', 'complex', 'matrix', 'range', 'string', 'unit' - ] -}; diff --git a/src/docs/function/construction/range.js b/src/docs/function/construction/range.js deleted file mode 100644 index 1b8e5512c..000000000 --- a/src/docs/function/construction/range.js +++ /dev/null @@ -1,25 +0,0 @@ -module.exports = { - 'name': 'range', - 'category': 'Type', - 'syntax': [ - 'start:end', - 'start:step:end', - 'range(start, end)', - 'range(start, end, step)', - 'range(string)' - ], - 'description': - 'Create a range. Lower bound of the range is included, upper bound is excluded.', - 'examples': [ - '1:5', - '3:-1:-4', - 'range(3, 7)', - 'range(0, 12, 2)', - 'range("4:11")', - 'a = [0, 1, 2, 3; 4, 5, 6]', - 'a(1:2)' - ], - 'seealso': [ - 'boolean', 'complex', 'matrix', 'number', 'string', 'unit' - ] -}; diff --git a/src/docs/function/construction/string.js b/src/docs/function/construction/string.js deleted file mode 100644 index ceb6b42dd..000000000 --- a/src/docs/function/construction/string.js +++ /dev/null @@ -1,18 +0,0 @@ -module.exports = { - 'name': 'string', - 'category': 'Type', - 'syntax': [ - '"text"', - 'string(x)' - ], - 'description': - 'Create a string or convert a value to a string', - 'examples': [ - '"Hello World!"', - 'string(4.2)', - 'string(3 + 2i)' - ], - 'seealso': [ - 'boolean', 'complex', 'matrix', 'number', 'range', 'unit' - ] -}; diff --git a/src/docs/function/construction/unit.js b/src/docs/function/construction/unit.js deleted file mode 100644 index 5917182c9..000000000 --- a/src/docs/function/construction/unit.js +++ /dev/null @@ -1,20 +0,0 @@ -module.exports = { - 'name': 'unit', - 'category': 'Type', - 'syntax': [ - 'value unit', - 'unit(value, unit)', - 'unit(string)' - ], - 'description': - 'Create a unit.', - 'examples': [ - '5.5 mm', - '3 inch', - 'unit(7.1, "kilogram")', - 'unit("23 deg")' - ], - 'seealso': [ - 'boolean', 'complex', 'matrix', 'number', 'range', 'string' - ] -}; diff --git a/src/docs/function/matrix/concat.js b/src/docs/function/matrix/concat.js deleted file mode 100644 index 270fadf91..000000000 --- a/src/docs/function/matrix/concat.js +++ /dev/null @@ -1,20 +0,0 @@ -module.exports = { - 'name': 'concat', - 'category': 'Matrix', - 'syntax': [ - 'concat(a, b, c, ...)', - 'concat(a, b, c, ..., dim)' - ], - 'description': 'Concatenate matrices. By default, the matrices are concatenated by the first dimension. The dimension on which to concatenate can be provided as last argument.', - 'examples': [ - 'a = [1, 2; 5, 6]', - 'b = [3, 4; 7, 8]', - 'concat(a, b)', - '[a, b]', - 'concat(a, b, 2)', - '[a; b]' - ], - 'seealso': [ - 'det', 'diag', 'eye', 'inv', 'ones', 'size', 'squeeze', 'subset', 'transpose', 'zeros' - ] -}; diff --git a/src/docs/function/matrix/det.js b/src/docs/function/matrix/det.js deleted file mode 100644 index aafb283e2..000000000 --- a/src/docs/function/matrix/det.js +++ /dev/null @@ -1,15 +0,0 @@ -module.exports = { - 'name': 'det', - 'category': 'Matrix', - 'syntax': [ - 'det(x)' - ], - 'description': 'Calculate the determinant of a matrix', - 'examples': [ - 'det([1, 2; 3, 4])', - 'det([-2, 2, 3; -1, 1, 3; 2, 0, -1])' - ], - 'seealso': [ - 'concat', 'diag', 'eye', 'inv', 'ones', 'size', 'squeeze', 'subset', 'transpose', 'zeros' - ] -}; diff --git a/src/docs/function/matrix/diag.js b/src/docs/function/matrix/diag.js deleted file mode 100644 index 473d87530..000000000 --- a/src/docs/function/matrix/diag.js +++ /dev/null @@ -1,18 +0,0 @@ -module.exports = { - 'name': 'diag', - 'category': 'Matrix', - 'syntax': [ - 'diag(x)', - 'diag(x, k)' - ], - 'description': 'Create a diagonal matrix or retrieve the diagonal of a matrix. When x is a vector, a matrix with the vector values on the diagonal will be returned. When x is a matrix, a vector with the diagonal values of the matrix is returned.When k is provided, the k-th diagonal will be filled in or retrieved, if k is positive, the values are placed on the super diagonal. When k is negative, the values are placed on the sub diagonal.', - 'examples': [ - 'diag(1:4)', - 'diag(1:4, 1)', - 'a = [1, 2, 3; 4, 5, 6; 7, 8, 9]', - 'diag(a)' - ], - 'seealso': [ - 'concat', 'det', 'eye', 'inv', 'ones', 'size', 'squeeze', 'subset', 'transpose', 'zeros' - ] -}; diff --git a/src/docs/function/matrix/eye.js b/src/docs/function/matrix/eye.js deleted file mode 100644 index 5163b840d..000000000 --- a/src/docs/function/matrix/eye.js +++ /dev/null @@ -1,20 +0,0 @@ -module.exports = { - 'name': 'eye', - 'category': 'Matrix', - 'syntax': [ - 'eye(n)', - 'eye(m, n)', - 'eye([m, n])', - 'eye' - ], - 'description': 'Returns the identity matrix with size m-by-n. The matrix has ones on the diagonal and zeros elsewhere.', - 'examples': [ - 'eye(3)', - 'eye(3, 5)', - 'a = [1, 2, 3; 4, 5, 6]', - 'eye(size(a))' - ], - 'seealso': [ - 'concat', 'det', 'diag', 'inv', 'ones', 'size', 'squeeze', 'subset', 'transpose', 'zeros' - ] -}; diff --git a/src/docs/function/matrix/inv.js b/src/docs/function/matrix/inv.js deleted file mode 100644 index 2afe90f5f..000000000 --- a/src/docs/function/matrix/inv.js +++ /dev/null @@ -1,16 +0,0 @@ -module.exports = { - 'name': 'inv', - 'category': 'Matrix', - 'syntax': [ - 'inv(x)' - ], - 'description': 'Calculate the inverse of a matrix', - 'examples': [ - 'inv([1, 2; 3, 4])', - 'inv(4)', - '1 / 4' - ], - 'seealso': [ - 'concat', 'det', 'diag', 'eye', 'ones', 'size', 'squeeze', 'subset', 'transpose', 'zeros' - ] -}; diff --git a/src/docs/function/matrix/ones.js b/src/docs/function/matrix/ones.js deleted file mode 100644 index c2d7f31b1..000000000 --- a/src/docs/function/matrix/ones.js +++ /dev/null @@ -1,23 +0,0 @@ -module.exports = { - 'name': 'ones', - 'category': 'Matrix', - 'syntax': [ - 'ones(n)', - 'ones(m, n)', - 'ones(m, n, p, ...)', - 'ones([m, n])', - 'ones([m, n, p, ...])', - 'ones' - ], - 'description': 'Create a matrix containing ones.', - 'examples': [ - 'ones(3)', - 'ones(3, 5)', - 'ones([2,3]) * 4.5', - 'a = [1, 2, 3; 4, 5, 6]', - 'ones(size(a))' - ], - 'seealso': [ - 'concat', 'det', 'diag', 'eye', 'inv', 'size', 'squeeze', 'subset', 'transpose', 'zeros' - ] -}; diff --git a/src/docs/function/matrix/size.js b/src/docs/function/matrix/size.js deleted file mode 100644 index b41856a74..000000000 --- a/src/docs/function/matrix/size.js +++ /dev/null @@ -1,18 +0,0 @@ -module.exports = { - 'name': 'size', - 'category': 'Matrix', - 'syntax': [ - 'size(x)' - ], - 'description': 'Calculate the size of a matrix.', - 'examples': [ - 'size(2.3)', - 'size("hello world")', - 'a = [1, 2; 3, 4; 5, 6]', - 'size(a)', - 'size(1:6)' - ], - 'seealso': [ - 'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'squeeze', 'subset', 'transpose', 'zeros' - ] -}; diff --git a/src/docs/function/matrix/squeeze.js b/src/docs/function/matrix/squeeze.js deleted file mode 100644 index adfdd48f6..000000000 --- a/src/docs/function/matrix/squeeze.js +++ /dev/null @@ -1,17 +0,0 @@ -module.exports = { - 'name': 'squeeze', - 'category': 'Matrix', - 'syntax': [ - 'squeeze(x)' - ], - 'description': 'Remove singleton dimensions from a matrix.', - 'examples': [ - 'a = zeros(1,3,2)', - 'size(squeeze(a))', - 'b = zeros(3,1,1)', - 'size(squeeze(b))' - ], - 'seealso': [ - 'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'size', 'subset', 'transpose', 'zeros' - ] -}; diff --git a/src/docs/function/matrix/subset.js b/src/docs/function/matrix/subset.js deleted file mode 100644 index a99f11e69..000000000 --- a/src/docs/function/matrix/subset.js +++ /dev/null @@ -1,23 +0,0 @@ -module.exports = { - 'name': 'subset', - 'category': 'Matrix', - 'syntax': [ - 'value(index)', - 'value(index) = replacement', - 'subset(value, [index])', - 'subset(value, [index], replacement)' - ], - 'description': 'Get or set a subset of a matrix or string.', - 'examples': [ - 'd = [1, 2; 3, 4]', - 'e = []', - 'e(0, 0:1) = [5, 6]', - 'e(1, :) = [7, 8]', - 'f = d * e', - 'f(1, 0)', - 'f(:, 0)' - ], - 'seealso': [ - 'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'range', 'size', 'squeeze', 'transpose', 'zeros' - ] -}; diff --git a/src/docs/function/matrix/transpose.js b/src/docs/function/matrix/transpose.js deleted file mode 100644 index f0fbca22e..000000000 --- a/src/docs/function/matrix/transpose.js +++ /dev/null @@ -1,17 +0,0 @@ -module.exports = { - 'name': 'transpose', - 'category': 'Matrix', - 'syntax': [ - 'x\'', - 'transpose(x)' - ], - 'description': 'Transpose a matrix', - 'examples': [ - 'a = [1, 2, 3; 4, 5, 6]', - 'a\'', - 'transpose(a)' - ], - 'seealso': [ - 'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'size', 'squeeze', 'subset', 'zeros' - ] -}; diff --git a/src/docs/function/matrix/zeros.js b/src/docs/function/matrix/zeros.js deleted file mode 100644 index 4a4506bbc..000000000 --- a/src/docs/function/matrix/zeros.js +++ /dev/null @@ -1,22 +0,0 @@ -module.exports = { - 'name': 'zeros', - 'category': 'Matrix', - 'syntax': [ - 'zeros(n)', - 'zeros(m, n)', - 'zeros(m, n, p, ...)', - 'zeros([m, n])', - 'zeros([m, n, p, ...])', - 'zeros' - ], - 'description': 'Create a matrix containing zeros.', - 'examples': [ - 'zeros(3)', - 'zeros(3, 5)', - 'a = [1, 2, 3; 4, 5, 6]', - 'zeros(size(a))' - ], - 'seealso': [ - 'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'size', 'squeeze', 'subset', 'transpose' - ] -}; diff --git a/src/docs/function/probability/factorial.js b/src/docs/function/probability/factorial.js deleted file mode 100644 index dc146cda0..000000000 --- a/src/docs/function/probability/factorial.js +++ /dev/null @@ -1,15 +0,0 @@ -module.exports = { - 'name': 'factorial', - 'category': 'Probability', - 'syntax': [ - 'x!', - 'factorial(x)' - ], - 'description': 'Compute the factorial of a value', - 'examples': [ - '5!', - '5*4*3*2*1', - '3!' - ], - 'seealso': [] -}; diff --git a/src/docs/function/probability/random.js b/src/docs/function/probability/random.js deleted file mode 100644 index 9a04f643c..000000000 --- a/src/docs/function/probability/random.js +++ /dev/null @@ -1,13 +0,0 @@ -module.exports = { - 'name': 'random', - 'category': 'Probability', - 'syntax': [ - 'random(min, max)' - ], - 'description': - 'Return a random number between 0 and 1.', - 'examples': [ - 'random()' - ], - 'seealso': [] -}; diff --git a/src/docs/function/probability/randomInt.js b/src/docs/function/probability/randomInt.js deleted file mode 100644 index f0da378e8..000000000 --- a/src/docs/function/probability/randomInt.js +++ /dev/null @@ -1,13 +0,0 @@ -module.exports = { - 'name': 'randInt', - 'category': 'Probability', - 'syntax': [ - 'randInt()' - ], - 'description': - 'Return a random number between 0 and 1.', - 'examples': [ - 'randInt()' - ], - 'seealso': [] -}; \ No newline at end of file diff --git a/src/docs/function/statistics/max.js b/src/docs/function/statistics/max.js deleted file mode 100644 index 5941a0e72..000000000 --- a/src/docs/function/statistics/max.js +++ /dev/null @@ -1,22 +0,0 @@ -module.exports = { - 'name': 'max', - 'category': 'Statistics', - 'syntax': [ - 'max(a, b, c, ...)' - ], - 'description': 'Compute the maximum value of a list of values.', - 'examples': [ - 'max(2, 3, 4, 1)', - 'max(2.7, 7.1, -4.5, 2.0, 4.1)', - 'min(2.7, 7.1, -4.5, 2.0, 4.1)' - ], - 'seealso': [ - //'sum', - //'prod', - //'avg', - //'var', - //'std', - 'min' - //'median' - ] -}; diff --git a/src/docs/function/statistics/min.js b/src/docs/function/statistics/min.js deleted file mode 100644 index adfb7f487..000000000 --- a/src/docs/function/statistics/min.js +++ /dev/null @@ -1,22 +0,0 @@ -module.exports = { - 'name': 'min', - 'category': 'Statistics', - 'syntax': [ - 'min(a, b, c, ...)' - ], - 'description': 'Compute the minimum value of a list of values.', - 'examples': [ - 'min(2, 3, 4, 1)', - 'min(2.7, 7.1, -4.5, 2.0, 4.1)', - 'max(2.7, 7.1, -4.5, 2.0, 4.1)' - ], - 'seealso': [ - //'sum', - //'prod', - //'avg', - //'var', - //'std', - 'max' - //'median' - ] -}; diff --git a/src/docs/function/trigonometry/acos.js b/src/docs/function/trigonometry/acos.js deleted file mode 100644 index 78ffe9da6..000000000 --- a/src/docs/function/trigonometry/acos.js +++ /dev/null @@ -1,17 +0,0 @@ -module.exports = { - 'name': 'acos', - 'category': 'Trigonometry', - 'syntax': [ - 'acos(x)' - ], - 'description': 'Compute the inverse cosine of a value in radians.', - 'examples': [ - 'acos(0.5)', - 'acos(cos(2.3))' - ], - 'seealso': [ - 'cos', - 'acos', - 'asin' - ] -}; diff --git a/src/docs/function/trigonometry/asin.js b/src/docs/function/trigonometry/asin.js deleted file mode 100644 index 6e53189e0..000000000 --- a/src/docs/function/trigonometry/asin.js +++ /dev/null @@ -1,17 +0,0 @@ -module.exports = { - 'name': 'asin', - 'category': 'Trigonometry', - 'syntax': [ - 'asin(x)' - ], - 'description': 'Compute the inverse sine of a value in radians.', - 'examples': [ - 'asin(0.5)', - 'asin(sin(2.3))' - ], - 'seealso': [ - 'sin', - 'acos', - 'asin' - ] -}; diff --git a/src/docs/function/trigonometry/atan.js b/src/docs/function/trigonometry/atan.js deleted file mode 100644 index 4780256da..000000000 --- a/src/docs/function/trigonometry/atan.js +++ /dev/null @@ -1,17 +0,0 @@ -module.exports = { - 'name': 'atan', - 'category': 'Trigonometry', - 'syntax': [ - 'atan(x)' - ], - 'description': 'Compute the inverse tangent of a value in radians.', - 'examples': [ - 'atan(0.5)', - 'atan(tan(2.3))' - ], - 'seealso': [ - 'tan', - 'acos', - 'asin' - ] -}; diff --git a/src/docs/function/trigonometry/atan2.js b/src/docs/function/trigonometry/atan2.js deleted file mode 100644 index da6dc5a29..000000000 --- a/src/docs/function/trigonometry/atan2.js +++ /dev/null @@ -1,21 +0,0 @@ -module.exports = { - 'name': 'atan2', - 'category': 'Trigonometry', - 'syntax': [ - 'atan2(y, x)' - ], - 'description': - 'Computes the principal value of the arc tangent of y/x in radians.', - 'examples': [ - 'atan2(2, 2) / pi', - 'angle = 60 deg in rad', - 'x = cos(angle)', - 'y = sin(angle)', - 'atan2(y, x)' - ], - 'seealso': [ - 'sin', - 'cos', - 'tan' - ] -}; diff --git a/src/docs/function/trigonometry/cos.js b/src/docs/function/trigonometry/cos.js deleted file mode 100644 index 412df2baf..000000000 --- a/src/docs/function/trigonometry/cos.js +++ /dev/null @@ -1,20 +0,0 @@ -module.exports = { - 'name': 'cos', - 'category': 'Trigonometry', - 'syntax': [ - 'cos(x)' - ], - 'description': 'Compute the cosine of x in radians.', - 'examples': [ - 'cos(2)', - 'cos(pi / 4) ^ 2', - 'cos(180 deg)', - 'cos(60 deg)', - 'sin(0.2)^2 + cos(0.2)^2' - ], - 'seealso': [ - 'acos', - 'sin', - 'tan' - ] -}; diff --git a/src/docs/function/trigonometry/cot.js b/src/docs/function/trigonometry/cot.js deleted file mode 100644 index 1d7fa12b8..000000000 --- a/src/docs/function/trigonometry/cot.js +++ /dev/null @@ -1,17 +0,0 @@ -module.exports = { - 'name': 'cot', - 'category': 'Trigonometry', - 'syntax': [ - 'cot(x)' - ], - 'description': 'Compute the cotangent of x in radians. Defined as 1/tan(x)', - 'examples': [ - 'cot(2)', - '1 / tan(2)' - ], - 'seealso': [ - 'sec', - 'csc', - 'tan' - ] -}; diff --git a/src/docs/function/trigonometry/csc.js b/src/docs/function/trigonometry/csc.js deleted file mode 100644 index bfe7d6fde..000000000 --- a/src/docs/function/trigonometry/csc.js +++ /dev/null @@ -1,17 +0,0 @@ -module.exports = { - 'name': 'csc', - 'category': 'Trigonometry', - 'syntax': [ - 'csc(x)' - ], - 'description': 'Compute the cosecant of x in radians. Defined as 1/sin(x)', - 'examples': [ - 'csc(2)', - '1 / sin(2)' - ], - 'seealso': [ - 'sec', - 'cot', - 'sin' - ] -}; diff --git a/src/docs/function/trigonometry/sec.js b/src/docs/function/trigonometry/sec.js deleted file mode 100644 index 9b931aa6a..000000000 --- a/src/docs/function/trigonometry/sec.js +++ /dev/null @@ -1,17 +0,0 @@ -module.exports = { - 'name': 'sec', - 'category': 'Trigonometry', - 'syntax': [ - 'sec(x)' - ], - 'description': 'Compute the secant of x in radians. Defined as 1/cos(x)', - 'examples': [ - 'sec(2)', - '1 / cos(2)' - ], - 'seealso': [ - 'cot', - 'csc', - 'cos' - ] -}; diff --git a/src/docs/function/trigonometry/sin.js b/src/docs/function/trigonometry/sin.js deleted file mode 100644 index 6d6f7f7a8..000000000 --- a/src/docs/function/trigonometry/sin.js +++ /dev/null @@ -1,20 +0,0 @@ -module.exports = { - 'name': 'sin', - 'category': 'Trigonometry', - 'syntax': [ - 'sin(x)' - ], - 'description': 'Compute the sine of x in radians.', - 'examples': [ - 'sin(2)', - 'sin(pi / 4) ^ 2', - 'sin(90 deg)', - 'sin(30 deg)', - 'sin(0.2)^2 + cos(0.2)^2' - ], - 'seealso': [ - 'asin', - 'cos', - 'tan' - ] -}; diff --git a/src/docs/function/trigonometry/tan.js b/src/docs/function/trigonometry/tan.js deleted file mode 100644 index 14c281982..000000000 --- a/src/docs/function/trigonometry/tan.js +++ /dev/null @@ -1,19 +0,0 @@ -module.exports = { - 'name': 'tan', - 'category': 'Trigonometry', - 'syntax': [ - 'tan(x)' - ], - 'description': 'Compute the tangent of x in radians.', - 'examples': [ - 'tan(0.5)', - 'sin(0.5) / cos(0.5)', - 'tan(pi / 4)', - 'tan(45 deg)' - ], - 'seealso': [ - 'atan', - 'sin', - 'cos' - ] -}; diff --git a/src/docs/function/units/in.js b/src/docs/function/units/in.js deleted file mode 100644 index 572c7f350..000000000 --- a/src/docs/function/units/in.js +++ /dev/null @@ -1,15 +0,0 @@ -module.exports = { - 'name': 'in', - 'category': 'Units', - 'syntax': [ - 'x in unit', - 'in(x, unit)' - ], - 'description': 'Change the unit of a value.', - 'examples': [ - '5 inch in cm', - '3.2kg in g', - '16 bytes in bits' - ], - 'seealso': [] -}; diff --git a/src/docs/function/utils/clone.js b/src/docs/function/utils/clone.js deleted file mode 100644 index 18ca109c3..000000000 --- a/src/docs/function/utils/clone.js +++ /dev/null @@ -1,16 +0,0 @@ -module.exports = { - 'name': 'clone', - 'category': 'Utils', - 'syntax': [ - 'clone(x)' - ], - 'description': 'Clone a variable. Creates a copy of primitive variables,and a deep copy of matrices', - 'examples': [ - 'clone(3.5)', - 'clone(2 - 4i)', - 'clone(45 deg)', - 'clone([1, 2; 3, 4])', - 'clone("hello world")' - ], - 'seealso': [] -}; diff --git a/src/docs/function/utils/eval.js b/src/docs/function/utils/eval.js deleted file mode 100644 index 0eba6892e..000000000 --- a/src/docs/function/utils/eval.js +++ /dev/null @@ -1,14 +0,0 @@ -module.exports = { - 'name': 'eval', - 'category': 'Utils', - 'syntax': [ - 'eval(expression)', - 'eval([expr1, expr2, expr3, ...])' - ], - 'description': 'Evaluate an expression or an array with expressions.', - 'examples': [ - 'eval("2 + 3")', - 'eval("sqrt(" + 4 + ")")' - ], - 'seealso': [] -}; diff --git a/src/docs/function/utils/format.js b/src/docs/function/utils/format.js deleted file mode 100644 index 98ad21f5f..000000000 --- a/src/docs/function/utils/format.js +++ /dev/null @@ -1,14 +0,0 @@ -module.exports = { - 'name': 'format', - 'category': 'Utils', - 'syntax': [ - 'format(value)' - ], - 'description': 'Format a value of any type as string.', - 'examples': [ - 'format(2.3)', - 'format(3 - 4i)', - 'format([])' - ], - 'seealso': [] -}; diff --git a/src/docs/function/utils/help.js b/src/docs/function/utils/help.js deleted file mode 100644 index 20a011a0b..000000000 --- a/src/docs/function/utils/help.js +++ /dev/null @@ -1,14 +0,0 @@ -module.exports = { - 'name': 'help', - 'category': 'Utils', - 'syntax': [ - 'help(object)', - 'help(string)' - ], - 'description': 'Display documentation on a function or data type.', - 'examples': [ - 'help(sqrt)', - 'help("complex")' - ], - 'seealso': [] -}; diff --git a/src/docs/function/utils/import.js b/src/docs/function/utils/import.js deleted file mode 100644 index b9efc92cf..000000000 --- a/src/docs/function/utils/import.js +++ /dev/null @@ -1,13 +0,0 @@ -module.exports = { - 'name': 'import', - 'category': 'Utils', - 'syntax': [ - 'import(string)' - ], - 'description': 'Import functions from a file.', - 'examples': [ - 'import("numbers")', - 'import("./mylib.js")' - ], - 'seealso': [] -}; diff --git a/src/docs/function/utils/typeof.js b/src/docs/function/utils/typeof.js deleted file mode 100644 index 71e329bc9..000000000 --- a/src/docs/function/utils/typeof.js +++ /dev/null @@ -1,15 +0,0 @@ -module.exports = { - 'name': 'typeof', - 'category': 'Utils', - 'syntax': [ - 'typeof(x)' - ], - 'description': 'Get the type of a variable.', - 'examples': [ - 'typeof(3.5)', - 'typeof(2 - 4i)', - 'typeof(45 deg)', - 'typeof("hello world")' - ], - 'seealso': [] -}; diff --git a/src/docs/index.js b/src/docs/index.js deleted file mode 100644 index 21b82313b..000000000 --- a/src/docs/index.js +++ /dev/null @@ -1,110 +0,0 @@ -// constants -exports.e = require('./constants/e.js'); -exports.E = require('./constants/e.js'); -exports['false'] = require('./constants/false.js'); -exports.i = require('./constants/i.js'); -exports['Infinity'] = require('./constants/Infinity.js'); -exports.LN2 = require('./constants/LN2.js'); -exports.LN10 = require('./constants/LN10.js'); -exports.LOG2E = require('./constants/LOG2E.js'); -exports.LOG10E = require('./constants/LOG10E.js'); -exports.NaN = require('./constants/NaN.js'); -exports.pi = require('./constants/pi.js'); -exports.PI = require('./constants/pi.js'); -exports.SQRT1_2 = require('./constants/SQRT1_2.js'); -exports.SQRT2 = require('./constants/SQRT2.js'); -exports.tau = require('./constants/tau.js'); -exports['true'] = require('./constants/true.js'); - -// functions - arithmetic -exports.abs = require('./function/arithmetic/abs.js'); -exports.add = require('./function/arithmetic/add.js'); -exports.ceil = require('./function/arithmetic/ceil.js'); -exports.cube = require('./function/arithmetic/cube.js'); -exports.divide = require('./function/arithmetic/divide.js'); -exports.edivide = require('./function/arithmetic/edivide.js'); -exports.emultiply = require('./function/arithmetic/emultiply.js'); -exports.epow = require('./function/arithmetic/epow.js'); -exports.equal = require('./function/arithmetic/equal.js'); -exports.exp = require('./function/arithmetic/exp.js'); -exports.fix = require('./function/arithmetic/fix.js'); -exports.floor = require('./function/arithmetic/floor.js'); -exports.gcd = require('./function/arithmetic/gcd.js'); -exports.larger = require('./function/arithmetic/larger.js'); -exports.largereq = require('./function/arithmetic/largereq.js'); -exports.lcm = require('./function/arithmetic/lcm.js'); -exports.log = require('./function/arithmetic/log.js'); -exports.log10 = require('./function/arithmetic/log10.js'); -exports.mod = require('./function/arithmetic/mod.js'); -exports.multiply = require('./function/arithmetic/multiply.js'); -exports.pow = require('./function/arithmetic/pow.js'); -exports.round = require('./function/arithmetic/round.js'); -exports.sign = require('./function/arithmetic/sign.js'); -exports.smaller = require('./function/arithmetic/smaller.js'); -exports.smallereq = require('./function/arithmetic/smallereq.js'); -exports.sqrt = require('./function/arithmetic/sqrt.js'); -exports.square = require('./function/arithmetic/square.js'); -exports.subtract = require('./function/arithmetic/subtract.js'); -exports.unary = require('./function/arithmetic/unary.js'); -exports.unequal = require('./function/arithmetic/unequal.js'); -exports.xgcd = require('./function/arithmetic/xgcd.js'); - -// functions - complex -exports.arg = require('./function/complex/arg.js'); -exports.conj = require('./function/complex/conj.js'); -exports.re = require('./function/complex/re.js'); -exports.im = require('./function/complex/im.js'); - -// functions - construction -exports.boolean = require('./function/construction/boolean.js'); -exports.complex = require('./function/construction/complex.js'); -exports.matrix = require('./function/construction/matrix.js'); -exports.number = require('./function/construction/number.js'); -exports.range = require('./function/construction/range.js'); -exports.string = require('./function/construction/string.js'); -exports.unit = require('./function/construction/unit.js'); - -// functions - matrix -exports.concat = require('./function/matrix/concat.js'); -exports.det = require('./function/matrix/det.js'); -exports.diag = require('./function/matrix/diag.js'); -exports.eye = require('./function/matrix/eye.js'); -exports.inv = require('./function/matrix/inv.js'); -exports.ones = require('./function/matrix/ones.js'); -exports.size = require('./function/matrix/size.js'); -exports.squeeze = require('./function/matrix/squeeze.js'); -exports.subset = require('./function/matrix/subset.js'); -exports.transpose = require('./function/matrix/transpose.js'); -exports.zeros = require('./function/matrix/zeros.js'); - -// functions - probability -exports.factorial = require('./function/probability/factorial.js'); -exports.random = require('./function/probability/random.js'); -exports.randomInt = require('./function/probability/randomInt.js'); - -// functions - statistics -exports.min = require('./function/statistics/min.js'); -exports.max = require('./function/statistics/max.js'); - -// functions - trigonometry -exports.acos = require('./function/trigonometry/acos.js'); -exports.asin = require('./function/trigonometry/asin.js'); -exports.atan = require('./function/trigonometry/atan.js'); -exports.atan2 = require('./function/trigonometry/atan2.js'); -exports.cos = require('./function/trigonometry/cos.js'); -exports.cot = require('./function/trigonometry/cot.js'); -exports.csc = require('./function/trigonometry/csc.js'); -exports.sec = require('./function/trigonometry/sec.js'); -exports.sin = require('./function/trigonometry/sin.js'); -exports.tan = require('./function/trigonometry/tan.js'); - -// functions - units -exports['in'] = require('./function/units/in.js'); - -// functions - utils -exports.clone = require('./function/utils/clone.js'); -exports['eval'] = require('./function/utils/eval.js'); -exports.format = require('./function/utils/format.js'); -exports.help = require('./function/utils/help.js'); -exports['import'] = require('./function/utils/import.js'); -exports['typeof'] = require('./function/utils/typeof.js'); diff --git a/src/exports.js b/src/exports.js deleted file mode 100644 index 3e5226c69..000000000 --- a/src/exports.js +++ /dev/null @@ -1,30 +0,0 @@ -/** - * CommonJS module exports - */ -if ((typeof module !== 'undefined') && (typeof module.exports !== 'undefined')) { - module.exports = math; -} -if (typeof exports !== 'undefined') { - exports = math; -} - -/** - * AMD module exports - */ -if (typeof(require) !== 'undefined' && typeof(define) !== 'undefined') { - define(function () { - return math; - }); -} - -/** - * Browser exports - */ -if (typeof(window) !== 'undefined') { - if (window['math']) { - object.deepExtend(window['math'], math); - } - else { - window['math'] = math; - } -} diff --git a/src/expr/Parser.js b/src/expr/Parser.js deleted file mode 100644 index 60f9c87cc..000000000 --- a/src/expr/Parser.js +++ /dev/null @@ -1,122 +0,0 @@ -var Scope = require('./Scope.js'); - -/** - * @constructor Parser - * Parser contains methods to evaluate or parse expressions, and has a number - * of convenience methods to get, set, and remove variables from memory. Parser - * keeps a scope containing variables in memory, which is used for all - * evaluations. - * - * Methods: - * var result = parser.eval(expr); // evaluate an expression - * var value = parser.get(name); // retrieve a variable from the parser - * parser.set(name, value); // set a variable in the parser - * parser.remove(name); // clear a variable from the - * // parsers scope - * parser.clear(); // clear the parsers scope - * - * // it is possible to parse an expression into a node tree: - * var node = parser.parse(expr); // parse an expression into a node tree - * var result = node.eval(); // evaluate a parsed node - * - * Example usage: - * var parser = new Parser(math); - * // Note: there is a convenience method which can be used instead: - * // var parser = new math.parser(); - * - * // evaluate expressions - * parser.eval('sqrt(3^2 + 4^2)'); // 5 - * parser.eval('sqrt(-4)'); // 2i - * parser.eval('2 inch in cm'); // 5.08 cm - * parser.eval('cos(45 deg)'); // 0.7071067811865476 - * - * // define variables and functions - * parser.eval('x = 7 / 2'); // 3.5 - * parser.eval('x + 3'); // 6.5 - * parser.eval('function f(x, y) = x^y'); // f(x, y) - * parser.eval('f(2, 3)'); // 8 - * - * // get and set variables and functions - * var x = parser.get('x'); // 7 - * var f = parser.get('f'); // function - * var g = f(3, 2); // 9 - * parser.set('h', 500); - * var i = parser.eval('h / 2'); // 250 - * parser.set('hello', function (name) { - * return 'hello, ' + name + '!'; - * }); - * parser.eval('hello("user")'); // "hello, user!" - * - * // clear defined functions and variables - * parser.clear(); - * - * - * @param {Object} math Link to the math.js namespace - */ -function Parser(math) { - if (!(this instanceof Parser)) { - throw new SyntaxError( - 'Parser constructor must be called with the new operator'); - } - - this.math = math; - this.scope = new Scope(math); -} - -/** - * Parse an expression end return the parsed function node. - * The node can be evaluated via node.eval() - * @param {String} expr - * @return {Node} node - * @throws {Error} - */ -Parser.prototype.parse = function (expr) { - return this.math.parse(expr, this.scope); -}; - -/** - * Parse and evaluate the given expression - * @param {String} expr A string containing an expression, for example "2+3" - * @return {*} result The result, or undefined when the expression was empty - * @throws {Error} - */ -Parser.prototype.eval = function (expr) { - var node = this.math.parse(expr, this.scope); - return node.eval(); -}; - -/** - * Get a variable (a function or variable) by name from the parsers scope. - * Returns undefined when not found - * @param {String} name - * @return {* | undefined} value - */ -Parser.prototype.get = function (name) { - return this.scope.get(name); -}; - -/** - * Set a symbol (a function or variable) by name from the parsers scope. - * @param {String} name - * @param {* | undefined} value - */ -Parser.prototype.set = function (name, value) { - this.scope.set(name, value); -}; - -/** - * Remove a variable from the parsers scope - * @param {String} name - */ -Parser.prototype.remove = function (name) { - this.scope.remove(name); -}; - -/** - * Clear the scope with variables and functions - */ -Parser.prototype.clear = function () { - this.scope.clear(); -}; - -module.exports = Parser; diff --git a/src/expr/Scope.js b/src/expr/Scope.js deleted file mode 100644 index 665eb2904..000000000 --- a/src/expr/Scope.js +++ /dev/null @@ -1,187 +0,0 @@ -var Unit = require('../type/Unit.js'); - -/** - * Scope - * A scope stores values of symbols: variables and functions. - * - * Syntax: - * var scope = new Scope(math); - * var scope = new Scope(math, parentScope); - * var scope = new Scope(math, symbols); - * var scope = new Scope(math, parentScope, symbols); - * - * Where: - * {Object} math Link to the (static) math.js namespace - * {Scope | Object} parentScope Scope will be linked to a parent scope, - * which is traversed when resolving - * symbols. - * {Object} symbols A custom object that will be used to - * resolve and store variables. - * - * @constructor Scope - * @param {...} [math] - * @param {*} [arg1] - * @param {*} [arg2] - */ -function Scope(math, arg1, arg2) { - this.math = math; - - /** @type {Scope} */ - this.parentScope = null; - // TODO: rename parentScope to previousScope, add a nextScope, change Scope to a linked list node - - /** @type {Scope[]} */ - this.subScopes = null; - // TODO: rename subScopes to childScopes (or childNodes?) - - /** @type {Object.} */ - this.symbols = {}; // variables and functions - - /** @type {Object.} */ - this.cache = {}; // cache, referring to the scope.symbols object where - // a variable was last found - - // read second argument (can be parentScope or symbols map) - if (arg1) { - if (arg1 instanceof Scope) { - this.parentScope = arg1; - } - else if (arg1 instanceof Object) { - this.symbols = arg1; - } - } - - // read second argument (can be symbols map) - if (arg2) { - if (arg2 instanceof Object) { - this.symbols = arg2; - } - } -} - -Scope.prototype = { - /** - * Create a sub scope - * The variables in a sub scope are not accessible from the parent scope - * @return {Scope} subScope - */ - createSubScope: function () { - var subScope = new Scope(this.math, this); - if (!this.subScopes) { - this.subScopes = []; - } - this.subScopes.push(subScope); - return subScope; - }, - - /** - * Get a symbol value by name. - * Returns undefined if the symbol is not found in this scope or any of - * its parent scopes. - * @param {String} name - * @returns {* | undefined} value - */ - get: function (name) { - var value; - - // check itself - value = this.symbols[name]; - if (value !== undefined) { - return value; - } - - // read from cache - var symbols = this.cache[name]; - if (symbols) { - return symbols[name]; - } - - // check parent scope - var parent = this.parentScope; - while (parent) { - value = parent.symbols[name]; - if (value !== undefined) { - this.cache[name] = parent.symbols; - return value; - } - parent = parent.parentScope; - } - - // check static context - value = this.math[name]; - if (value !== undefined) { - this.cache[name] = this.math; - return value; - } - - // check if name is a unit - if (Unit.isPlainUnit(name)) { - value = new Unit(null, name); - this.cache[name] = {}; - this.cache[name][name] = value; - return value; - } - - return undefined; - }, - - /** - * Test whether this scope contains a symbol (will not check parent scopes) - * @param {String} name - * @return {Boolean} hasSymbol - */ - has: function (name) { - return (this.symbols[name] !== undefined); - }, - - /** - * Set a symbol value - * @param {String} name - * @param {*} value - * @return {*} value - */ - set: function (name, value) { - return this.symbols[name] = value; - }, - - /** - * Remove a symbol by name - * @param {String} name - */ - remove: function(name) { - delete this.symbols[name]; - }, - - /** - * Clear all symbols in this scope, its sub scopes, and clear the cache. - * Parent scopes will not be cleared. - */ - clear: function () { - var symbols = this.symbols; - for (var name in symbols) { - if (symbols.hasOwnProperty(name)) { - delete symbols[name]; - } - } - - if (this.subScopes) { - var subScopes = this.subScopes; - for (var i = 0, iMax = subScopes.length; i < iMax; i++) { - subScopes[i].clear(); - } - } - - this.clearCache(); - }, - - /** - * Clear cached links to symbols in other scopes - */ - clearCache: function () { - this.cache = {}; - } -}; - -Scope.context = []; // static context, for example the math namespace - -module.exports = Scope; diff --git a/src/expr/Selector.js b/src/expr/Selector.js deleted file mode 100644 index 330f5fada..000000000 --- a/src/expr/Selector.js +++ /dev/null @@ -1,129 +0,0 @@ -module.exports = function (math) { - var util = require('../util/index.js'), - string = util.string; - - /** - * @constructor Selector - * Wrap any value in a Selector, allowing to perform chained operations on - * the value. - * - * All methods available in the math.js library can be called upon the selector, - * and then will be evaluated with the value itself as first argument. - * The selector can be closed by executing selector.done(), which will return - * the final value. - * - * The Selector has a number of special functions: - * - done() Finalize the chained operation and return the selectors value. - * - valueOf() The same as done() - * - toString() Executes math.format() onto the selectors value, returning - * a string representation of the value. - * - get(...) Get a subset of the selectors value. Useful for example for - * matrices and arrays. - * - set(...) Replace a subset of the selectors value. Useful for example for - * matrices and arrays. - * - * @param {*} [value] - */ - function Selector (value) { - if (!(this instanceof Selector)) { - throw new SyntaxError( - 'Selector constructor must be called with the new operator'); - } - - if (value instanceof Selector) { - this.value = value.value; - } - else { - this.value = value; - } - } - - Selector.prototype = { - /** - * Close the selector. Returns the final value. - * Does the same as method valueOf() - * @returns {*} value - */ - done: function () { - return this.value; - }, - - /** - * Get a submatrix or subselection from current value. - * Only applicable when the current value has a method get. - */ - get: function (index) { - var value = this.value; - if (!value) { - throw Error('Selector value is undefined'); - } - - return new Selector(math.subset(value, index)); - }, - - /** - * Set a submatrix or subselection on current value. - * Only applicable when the current value has a method set. - */ - set: function (index, replacement) { - var value = this.value; - if (!value) { - throw Error('Selector value is undefined'); - } - - return new Selector(math.subset(value, index, replacement)); - }, - - /** - * Close the selector. Returns the final value. - * Does the same as method done() - * @returns {*} value - */ - valueOf: function () { - return this.value; - }, - - /** - * Get the string representation of the value in the selector - * @returns {String} - */ - toString: function () { - return string.format(this.value); - } - }; - - /** - * Create a proxy method for the selector - * @param {String} name - * @param {*} value The value or function to be proxied - */ - function createProxy(name, value) { - var slice = Array.prototype.slice; - if (typeof value === 'function') { - // a function - Selector.prototype[name] = function () { - var args = [this.value].concat(slice.call(arguments, 0)); - return new Selector(value.apply(this, args)); - } - } - else { - // a constant - Selector.prototype[name] = new Selector(value); - } - } - - Selector.createProxy = createProxy; - - /** - * initialise the Chain prototype with all functions and constants in math - */ - for (var prop in math) { - if (math.hasOwnProperty(prop) && prop) { - createProxy(prop, math[prop]); - } - } - - util.types.addType('selector', Selector); - - return Selector; -}; diff --git a/src/expr/node/AssignmentNode.js b/src/expr/node/AssignmentNode.js deleted file mode 100644 index 871fb5e79..000000000 --- a/src/expr/node/AssignmentNode.js +++ /dev/null @@ -1,63 +0,0 @@ -var Node = require('./Node.js'); - -/** - * @constructor AssignmentNode - * Define a symbol, like "a = 3.2" - * - * @param {String} name Symbol name - * @param {Node} expr The expression defining the symbol - * @param {Scope} scope Scope to store the result - */ -function AssignmentNode(name, expr, scope) { - this.name = name; - this.expr = expr; - this.scope = scope; -} - -AssignmentNode.prototype = new Node(); - -/** - * Evaluate the assignment - * @return {*} result - */ -AssignmentNode.prototype.eval = function() { - if (this.expr === undefined) { - throw new Error('Undefined symbol ' + this.name); - } - - var result = this.expr.eval(); - this.scope.set(this.name, result); - - return result; -}; - -/** - * Find all nodes matching given filter - * @param {Object} filter See Node.find for a description of the filter options - * @returns {Node[]} nodes - */ -AssignmentNode.prototype.find = function (filter) { - var nodes = []; - - // check itself - if (this.match(filter)) { - nodes.push(this); - } - - // search in expression - if (this.expr) { - nodes = nodes.concat(this.expr.find(filter)); - } - - return nodes; -}; - -/** - * Get string representation - * @return {String} - */ -AssignmentNode.prototype.toString = function() { - return this.name + ' = ' + this.expr.toString(); -}; - -module.exports = AssignmentNode; \ No newline at end of file diff --git a/src/expr/node/BlockNode.js b/src/expr/node/BlockNode.js deleted file mode 100644 index bdb1ec758..000000000 --- a/src/expr/node/BlockNode.js +++ /dev/null @@ -1,85 +0,0 @@ -var Node = require('./Node.js'); - -/** - * @constructor BlockNode - * Holds a set with nodes - * @extends {Node} - */ -function BlockNode() { - this.params = []; - this.visible = []; -} - -BlockNode.prototype = new Node(); - -/** - * Add a parameter - * @param {Node} param - * @param {Boolean} [visible] true by default - */ -BlockNode.prototype.add = function (param, visible) { - var index = this.params.length; - this.params[index] = param; - this.visible[index] = (visible != undefined) ? visible : true; -}; - -/** - * Evaluate the set - * @return {*[]} results - * @override - */ -BlockNode.prototype.eval = function() { - // evaluate the parameters - var results = []; - for (var i = 0, iMax = this.params.length; i < iMax; i++) { - var result = this.params[i].eval(); - if (this.visible[i]) { - results.push(result); - } - } - - return results; -}; - -/** - * Find all nodes matching given filter - * @param {Object} filter See Node.find for a description of the filter options - * @returns {Node[]} nodes - */ -BlockNode.prototype.find = function (filter) { - var nodes = []; - - // check itself - if (this.match(filter)) { - nodes.push(this); - } - - // search in parameters - var params = this.params; - if (params) { - for (var i = 0, len = params.length; i < len; i++) { - nodes = nodes.concat(params[i].find(filter)); - } - } - - return nodes; -}; - -/** - * Get string representation - * @return {String} str - * @override - */ -BlockNode.prototype.toString = function() { - var strings = []; - - for (var i = 0, iMax = this.params.length; i < iMax; i++) { - if (this.visible[i]) { - strings.push('\n ' + this.params[i].toString()); - } - } - - return '[' + strings.join(',') + '\n]'; -}; - -module.exports = BlockNode; diff --git a/src/expr/node/ConstantNode.js b/src/expr/node/ConstantNode.js deleted file mode 100644 index e82d36580..000000000 --- a/src/expr/node/ConstantNode.js +++ /dev/null @@ -1,31 +0,0 @@ -var Node = require('./Node.js'), - string = require('../../util/string.js'); - -/** - * @constructor ConstantNode - * @param {*} value - * @extends {Node} - */ -function ConstantNode(value) { - this.value = value; -} - -ConstantNode.prototype = new Node(); - -/** - * Evaluate the constant (just return it) - * @return {*} value - */ -ConstantNode.prototype.eval = function () { - return this.value; -}; - -/** - * Get string representation - * @return {String} str - */ -ConstantNode.prototype.toString = function() { - return string.format(this.value); -}; - -module.exports = ConstantNode; diff --git a/src/expr/node/FunctionNode.js b/src/expr/node/FunctionNode.js deleted file mode 100644 index dad2400db..000000000 --- a/src/expr/node/FunctionNode.js +++ /dev/null @@ -1,87 +0,0 @@ -var Node = require('./Node.js'), - error = require('../../util/error.js'); - -/** - * @constructor FunctionNode - * Function assignment - * - * @param {String} name Function name - * @param {String[]} variables Variable names - * @param {Node} expr The function expression - * @param {Scope} functionScope Scope in which to write variable values - * @param {Scope} scope Scope to store the resulting function assignment - */ -function FunctionNode(name, variables, expr, functionScope, scope) { - this.name = name; - this.variables = variables; - this.expr = expr; - this.scope = scope; - - // create function - this.fn = function () { - var num = variables ? variables.length : 0; - - // validate correct number of arguments - if (arguments.length != num) { - throw new error.ArgumentsError(name, arguments.length, num); - } - - // fill in the provided arguments in the functionScope variables - for (var i = 0; i < num; i++) { - functionScope.set(variables[i], arguments[i]); - } - - // evaluate the expression - return expr.eval(); - }; - - this.fn.toString = function() { - // TODO: what to return as toString? - return name + '(' + variables.join(', ') + ')'; - //return name + '(' + variableNames.join(', ') + ') = ' + expr.toString(); - }; -} - -FunctionNode.prototype = new Node(); - -/** - * Evaluate the function assignment - * @return {function} fn - */ -FunctionNode.prototype.eval = function() { - // put the definition in the scope - this.scope.set(this.name, this.fn); - - return this.fn; -}; - -/** - * Find all nodes matching given filter - * @param {Object} filter See Node.find for a description of the filter options - * @returns {Node[]} nodes - */ -FunctionNode.prototype.find = function (filter) { - var nodes = []; - - // check itself - if (this.match(filter)) { - nodes.push(this); - } - - // search in expression - if (this.expr) { - nodes = nodes.concat(this.expr.find(filter)); - } - - return nodes; -}; - -/** - * get string representation - * @return {String} str - */ -FunctionNode.prototype.toString = function() { - return this.fn.toString(); -}; - -module.exports = FunctionNode; diff --git a/src/expr/node/MatrixNode.js b/src/expr/node/MatrixNode.js deleted file mode 100644 index 612f33d57..000000000 --- a/src/expr/node/MatrixNode.js +++ /dev/null @@ -1,155 +0,0 @@ -var Node = require('./Node.js'), - object = require('../../util/object.js'), - string = require('../../util/string.js'), - collection = require('../../type/collection.js'), - Matrix = require('../../type/Matrix.js'), - Range = require('../../type/Range.js'); - -/** - * @constructor MatrixNode - * Holds an 2-dimensional array with nodes - * @param {Array[]} nodes 2 dimensional array with nodes - * @extends {Node} - */ -function MatrixNode(nodes) { - this.nodes = nodes || []; -} - -MatrixNode.prototype = new Node(); - -/** - * Evaluate the array - * @return {Matrix} results - * @override - */ -MatrixNode.prototype.eval = function() { - // evaluate all nodes in the 2d array, and merge the results into a matrix - var nodes = this.nodes, - results = [], - mergeNeeded = false; - - for (var r = 0, rows = nodes.length; r < rows; r++) { - var nodes_r = nodes[r]; - var results_r = []; - for (var c = 0, cols = nodes_r.length; c < cols; c++) { - var results_rc = nodes_r[c].eval(); - if (collection.isCollection(results_rc)) { - mergeNeeded = true; - } - results_r[c] = results_rc; - } - results[r] = results_r; - } - - if (mergeNeeded) { - results = merge(results); - } - - return new Matrix(results); -}; - -/** - * Find all nodes matching given filter - * @param {Object} filter See Node.find for a description of the filter options - * @returns {Node[]} nodes - */ -MatrixNode.prototype.find = function (filter) { - var results = []; - - // check itself - if (this.match(filter)) { - results.push(this); - } - - // search in all nodes - var nodes = this.nodes; - for (var r = 0, rows = nodes.length; r < rows; r++) { - var nodes_r = nodes[r]; - for (var c = 0, cols = nodes_r.length; c < cols; c++) { - results = results.concat(nodes_r[c].find(filter)); - } - } - - return results; -}; - -/** - * Merge nested Matrices in a two dimensional Array. - * @param {Array} array Two-dimensional array containing Matrices - * @return {Array} merged The merged array (two-dimensional) - */ -function merge (array) { - var merged = []; - var rows = array.length; - for (var r = 0; r < rows; r++) { - var array_r = array[r]; - var cols = array_r.length; - var submatrix = null; - var submatrixRows = null; - for (var c = 0; c < cols; c++) { - var entry = object.clone(array_r[c]); - var size; - if (entry instanceof Matrix) { - // get the data from the matrix - size = entry.size(); - entry = entry.valueOf(); - if (size.length == 1) { - entry = [entry]; - size = [1, size[0]]; - } - else if (size.length > 2) { - throw new Error('Cannot merge a multi dimensional matrix'); - } - } - else if (entry instanceof Range) { - // change range into an 1xn matrix - entry = [entry.valueOf()]; - size = [1, entry[0].length]; - } - else if (Array.isArray(entry)) { - // change array into a 1xn matrix - size = [1, entry.length]; - entry = [entry]; - } - else { - // change scalar into a 1x1 matrix - size = [1, 1]; - entry = [[entry]]; - } - - // check the height of this row - if (submatrix == null) { - // first entry - submatrix = entry; - submatrixRows = size[0]; - } - else if (size[0] == submatrixRows) { - // merge - for (var s = 0; s < submatrixRows; s++) { - submatrix[s] = submatrix[s].concat(entry[s]); - } - } - else { - // no good... - throw new Error('Dimension mismatch ' + - '(' + size[0] + ' != ' + submatrixRows + ')'); - } - } - - // merge the submatrix - merged = merged.concat(submatrix); - } - - return merged; -} - -/** - * Get string representation - * @return {String} str - * @override - */ -MatrixNode.prototype.toString = function() { - return string.format(this.nodes); -}; - -module.exports = MatrixNode; diff --git a/src/expr/node/Node.js b/src/expr/node/Node.js deleted file mode 100644 index 12182c083..000000000 --- a/src/expr/node/Node.js +++ /dev/null @@ -1,71 +0,0 @@ -/** - * Node - */ -function Node() {} - -/** - * Evaluate the node - * @return {*} result - */ -Node.prototype.eval = function () { - throw new Error('Cannot evaluate a Node interface'); -}; - -/** - * Find any node in the node tree matching given filter. For example, to - * find all nodes of type SymbolNode having name 'x': - * - * var results = Node.find({ - * type: SymbolNode, - * properties: { - * name: 'x' - * } - * }); - * - * @param {Object} filter Available parameters: - * {Function} type - * {Object} properties - * @return {Node[]} nodes An array with nodes matching given filter criteria - */ -Node.prototype.find = function (filter) { - return this.match(filter) ? [this] : []; -}; - -/** - * Test if this object matches given filter - * @param {Object} filter Available parameters: - * {Function} type - * {Object} properties - * @return {Boolean} matches True if there is a match - */ -Node.prototype.match = function (filter) { - var match = true; - - if (filter) { - if (filter.type && !(this instanceof filter.type)) { - match = false; - } - if (match && filter.properties) { - for (var prop in filter.properties) { - if (filter.properties.hasOwnProperty(prop)) { - if (this[prop] != filter.properties[prop]) { - match = false; - break; - } - } - } - } - } - - return match; -}; - -/** - * Get string representation - * @return {String} - */ -Node.prototype.toString = function() { - return ''; -}; - -module.exports = Node; diff --git a/src/expr/node/OperatorNode.js b/src/expr/node/OperatorNode.js deleted file mode 100644 index 6b851056d..000000000 --- a/src/expr/node/OperatorNode.js +++ /dev/null @@ -1,86 +0,0 @@ -var Node = require('./Node.js'); - -/** - * @constructor OperatorNode - * An operator with two arguments, like 2+3 - * @param {String} name Function name, for example '+' - * @param {function} fn Function, for example math.add - * @param {Node[]} params Parameters - */ -function OperatorNode (name, fn, params) { - this.name = name; - this.fn = fn; - this.params = params; -} - -OperatorNode.prototype = new Node(); - -/** - * Evaluate the parameters - * @return {*} result - */ -OperatorNode.prototype.eval = function() { - return this.fn.apply(this, this.params.map(function (param) { - return param.eval(); - })); -}; - -/** - * Find all nodes matching given filter - * @param {Object} filter See Node.find for a description of the filter options - * @returns {Node[]} nodes - */ -OperatorNode.prototype.find = function (filter) { - var nodes = []; - - // check itself - if (this.match(filter)) { - nodes.push(this); - } - - // search in parameters - var params = this.params; - if (params) { - for (var i = 0, len = params.length; i < len; i++) { - nodes = nodes.concat(params[i].find(filter)); - } - } - - return nodes; -}; - -/** - * Get string representation - * @return {String} str - */ -OperatorNode.prototype.toString = function() { - var params = this.params; - - switch (params.length) { - case 1: - if (this.name == '-') { - // special case: unary minus - return '-' + params[0].toString(); - } - else { - // for example '5!' - return params[0].toString() + this.name; - } - - case 2: // for example '2+3' - var lhs = params[0].toString(); - if (params[0] instanceof OperatorNode) { - lhs = '(' + lhs + ')'; - } - var rhs = params[1].toString(); - if (params[1] instanceof OperatorNode) { - rhs = '(' + rhs + ')'; - } - return lhs + ' ' + this.name + ' ' + rhs; - - default: // this should occur. format as a function call - return this.name + '(' + this.params.join(', ') + ')'; - } -}; - -module.exports = OperatorNode; diff --git a/src/expr/node/ParamsNode.js b/src/expr/node/ParamsNode.js deleted file mode 100644 index e0fc0f990..000000000 --- a/src/expr/node/ParamsNode.js +++ /dev/null @@ -1,129 +0,0 @@ -var Node = require('./Node.js'), - SymbolNode = require('./SymbolNode.js').SymbolNode; - -/** - * @constructor ParamsNode - * invoke a list with parameters on the results of a node - * @param {Object} math The math namespace containing all functions - * @param {Node} object - * @param {Node[]} params - * @param {Scope[]} paramScopes A scope for every parameter, where the - * index variable 'end' can be defined. - */ -function ParamsNode (math, object, params, paramScopes) { - this.math = math; - - this.object = object; - this.params = params; - this.paramScopes = paramScopes; - - // check whether any of the params expressions uses the context symbol 'end' - this.hasContextParams = false; - if (params) { - var filter = { - type: SymbolNode, - properties: { - name: 'end' - } - }; - - for (var i = 0, len = params.length; i < len; i++) { - if (params[i].find(filter).length > 0) { - this.hasContextParams = true; - break; - } - } - } -} - -ParamsNode.prototype = new Node(); - -/** - * Evaluate the parameters - * @return {*} result - */ -ParamsNode.prototype.eval = function() { - var i, len; - - // evaluate the object - var object = this.object; - if (object == undefined) { - throw new Error ('Node undefined'); - } - var obj = object.eval(); - - // evaluate the values of context parameter 'end' when needed - if (this.hasContextParams) { - var paramScopes = this.paramScopes, - size = this.math.size(obj).valueOf(); - - if (paramScopes && size) { - for (i = 0, len = this.params.length; i < len; i++) { - var paramScope = paramScopes[i]; - if (paramScope) { - paramScope.set('end', size[i]); - } - } - } - } - - // evaluate the parameters - var params = this.params, - results = []; - for (i = 0, len = this.params.length; i < len; i++) { - results[i] = params[i].eval(); - } - - if (typeof obj === 'function') { - // invoke a function with the parameters - return obj.apply(this, results); - } - else { - // get a subset of the object - return this.math.subset(obj, results); - } -}; - -/** - * Find all nodes matching given filter - * @param {Object} filter See Node.find for a description of the filter options - * @returns {Node[]} nodes - */ -ParamsNode.prototype.find = function (filter) { - var nodes = []; - - // check itself - if (this.match(filter)) { - nodes.push(this); - } - - // search object - if (this.object) { - nodes = nodes.concat(this.object.find(filter)); - } - - // search in parameters - var params = this.params; - if (params) { - for (var i = 0, len = params.length; i < len; i++) { - nodes = nodes.concat(params[i].find(filter)); - } - } - - return nodes; -}; - -/** - * Get string representation - * @return {String} str - */ -ParamsNode.prototype.toString = function() { - // format the parameters like "(2, 4.2)" - var str = this.object ? this.object.toString() : ''; - if (this.params) { - str += '(' + this.params.join(', ') + ')'; - } - return str; -}; - -module.exports = ParamsNode; diff --git a/src/expr/node/SymbolNode.js b/src/expr/node/SymbolNode.js deleted file mode 100644 index ed1dfeaa8..000000000 --- a/src/expr/node/SymbolNode.js +++ /dev/null @@ -1,42 +0,0 @@ -var Node = require('./Node.js'); - -/** - * @constructor SymbolNode - * A symbol node can hold and resolve a symbol - * @param {String} name - * @param {Scope} scope - * @extends {Node} - */ -function SymbolNode(name, scope) { - this.name = name; - this.scope = scope; -} - -SymbolNode.prototype = new Node(); - -/** - * Evaluate the symbol. Throws an error when the symbol is undefined. - * @return {*} result - * @override - */ -SymbolNode.prototype.eval = function() { - // return the value of the symbol - var value = this.scope.get(this.name); - - if (value === undefined) { - throw new Error('Undefined symbol ' + this.name); - } - - return value; -}; - -/** - * Get string representation - * @return {String} str - * @override - */ -SymbolNode.prototype.toString = function() { - return this.name; -}; - -module.exports = SymbolNode; diff --git a/src/expr/node/UpdateNode.js b/src/expr/node/UpdateNode.js deleted file mode 100644 index c0fb3c3e7..000000000 --- a/src/expr/node/UpdateNode.js +++ /dev/null @@ -1,137 +0,0 @@ -var Node = require('./Node.js'), - SymbolNode = require('./SymbolNode.js').SymbolNode; - -/** - * @constructor UpdateNode - * Update a symbol value, like a(2,3) = 4.5 - * - * @param {Object} math The math namespace containing all functions - * @param {String} name Symbol name - * @param {Node[] | undefined} params One or more parameters - * @param {Scope[]} paramScopes A scope for every parameter, where the - * index variable 'end' can be defined. - * @param {Node} expr The expression defining the symbol - * @param {Scope} scope Scope to store the result - */ -function UpdateNode(math, name, params, paramScopes, expr, scope) { - this.math = math; - - this.name = name; - this.params = params; - this.paramScopes = paramScopes; - this.expr = expr; - this.scope = scope; - - // check whether any of the params expressions uses the context symbol 'end' - this.hasContextParams = false; - var filter = { - type: SymbolNode, - properties: { - name: 'end' - } - }; - for (var i = 0, len = params.length; i < len; i++) { - if (params[i].find(filter).length > 0) { - this.hasContextParams = true; - break; - } - } -} - -UpdateNode.prototype = new Node(); - -/** - * Evaluate the assignment - * @return {*} result - */ -UpdateNode.prototype.eval = function() { - if (this.expr === undefined) { - throw new Error('Undefined symbol ' + this.name); - } - - var result; - - // test if definition is currently undefined - var prevResult = this.scope.get(this.name); - if (prevResult == undefined) { - throw new Error('Undefined symbol ' + this.name); - } - - // evaluate the values of context parameter 'end' when needed - if (this.hasContextParams) { - var paramScopes = this.paramScopes, - size = this.math.size(prevResult).valueOf(); - - if (paramScopes && size) { - for (var i = 0, len = this.params.length; i < len; i++) { - var paramScope = paramScopes[i]; - if (paramScope) { - paramScope.set('end', size[i]); - } - } - } - } - - // change part of a matrix, for example "a=[]", "a(2,3)=4.5" - var paramResults = []; - this.params.forEach(function (param) { - paramResults.push(param.eval()); - }); - - var exprResult = this.expr.eval(); - - // replace subset - result = this.math.subset(prevResult, paramResults, exprResult); - - this.scope.set(this.name, result); - - return result; -}; - -/** - * Find all nodes matching given filter - * @param {Object} filter See Node.find for a description of the filter options - * @returns {Node[]} nodes - */ -UpdateNode.prototype.find = function (filter) { - var nodes = []; - - // check itself - if (this.match(filter)) { - nodes.push(this); - } - - // search in parameters - var params = this.params; - if (params) { - for (var i = 0, len = params.length; i < len; i++) { - nodes = nodes.concat(params[i].find(filter)); - } - } - - // search in expression - if (this.expr) { - nodes = nodes.concat(this.expr.find(filter)); - } - - return nodes; -}; - -/** - * Get string representation - * @return {String} - */ -UpdateNode.prototype.toString = function() { - var str = ''; - - str += this.name; - if (this.params && this.params.length) { - str += '(' + this.params.join(', ') + ')'; - } - str += ' = '; - str += this.expr.toString(); - - return str; -}; - -module.exports = UpdateNode; diff --git a/src/expr/node/handlers.js b/src/expr/node/handlers.js deleted file mode 100644 index d28776282..000000000 --- a/src/expr/node/handlers.js +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Custom node handlers, - * (can be added to the exports object) - */ diff --git a/src/expr/node/index.js b/src/expr/node/index.js deleted file mode 100644 index 68ffd9bd5..000000000 --- a/src/expr/node/index.js +++ /dev/null @@ -1,12 +0,0 @@ -exports.AssignmentNode = require('./AssignmentNode.js'); -exports.BlockNode = require('./BlockNode.js'); -exports.ConstantNode = require('./ConstantNode.js'); -exports.FunctionNode = require('./FunctionNode.js'); -exports.MatrixNode = require('./MatrixNode.js'); -exports.Node = require('./Node.js'); -exports.OperatorNode = require('./OperatorNode.js'); -exports.ParamsNode = require('./ParamsNode.js'); -exports.SymbolNode = require('./SymbolNode.js'); -exports.UpdateNode = require('./UpdateNode.js'); - -exports.handlers = require('./handlers.js'); diff --git a/src/function/arithmetic/abs.js b/src/function/arithmetic/abs.js deleted file mode 100644 index a83587f0e..000000000 --- a/src/function/arithmetic/abs.js +++ /dev/null @@ -1,46 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Complex = require('../../type/Complex.js'), - Matrix = require('../../type/Matrix.js'), - collection = require('../../type/collection.js'), - - isNumber = util.number.isNumber, - isComplex = Complex.isComplex, - isCollection = collection.isCollection; - - /** - * Calculate the absolute value of a value. - * - * abs(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ - math.abs = function abs(x) { - if (arguments.length != 1) { - throw new util.error.ArgumentsError('abs', arguments.length, 1); - } - - if (isNumber(x)) { - return Math.abs(x); - } - - if (isComplex(x)) { - return Math.sqrt(x.re * x.re + x.im * x.im); - } - - if (isCollection(x)) { - return collection.map(x, abs); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return abs(x.valueOf()); - } - - throw new util.error.UnsupportedTypeError('abs', x); - }; -}; diff --git a/src/function/arithmetic/add.js b/src/function/arithmetic/add.js deleted file mode 100644 index ab28653bf..000000000 --- a/src/function/arithmetic/add.js +++ /dev/null @@ -1,97 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Complex = require('../../type/Complex.js'), - Matrix = require('../../type/Matrix.js'), - Unit = require('../../type/Unit.js'), - collection = require('../../type/collection.js'), - - isNumber = util.number.isNumber, - isString = util.string.isString, - isComplex = Complex.isComplex, - isUnit = Unit.isUnit, - isCollection = collection.isCollection; - - /** - * Add two values - * - * x + y - * add(x, y) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Unit | String | Array | Matrix} x - * @param {Number | Complex | Unit | String | Array | Matrix} y - * @return {Number | Complex | Unit | String | Array | Matrix} res - */ - math.add = function add(x, y) { - if (arguments.length != 2) { - throw new util.error.ArgumentsError('add', arguments.length, 2); - } - - if (isNumber(x)) { - if (isNumber(y)) { - // number + number - return x + y; - } - else if (isComplex(y)) { - // number + complex - return Complex.create( - x + y.re, - y.im - ) - } - } - else if (isComplex(x)) { - if (isNumber(y)) { - // complex + number - return Complex.create( - x.re + y, - x.im - ) - } - else if (isComplex(y)) { - // complex + complex - return Complex.create( - x.re + y.re, - x.im + y.im - ); - } - } - else if (isUnit(x)) { - if (isUnit(y)) { - if (!x.equalBase(y)) { - throw new Error('Units do not match'); - } - - if (x.value == null) { - throw new Error('Unit on left hand side of operator + has an undefined value'); - } - - if (y.value == null) { - throw new Error('Unit on right hand side of operator + has an undefined value'); - } - - var res = x.clone(); - res.value += y.value; - res.fixPrefix = false; - return res; - } - } - - if (isString(x) || isString(y)) { - return x + y; - } - - if (isCollection(x) || isCollection(y)) { - return collection.map2(x, y, add); - } - - if (x.valueOf() !== x || y.valueOf() !== y) { - // fallback on the objects primitive value - return add(x.valueOf(), y.valueOf()); - } - - throw new util.error.UnsupportedTypeError('add', x, y); - }; -}; diff --git a/src/function/arithmetic/ceil.js b/src/function/arithmetic/ceil.js deleted file mode 100644 index 469335a24..000000000 --- a/src/function/arithmetic/ceil.js +++ /dev/null @@ -1,48 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Complex = require('../../type/Complex.js'), - collection = require('../../type/collection.js'), - - isNumber = util.number.isNumber, - isCollection =collection.isCollection, - isComplex = Complex.isComplex; - - /** - * Round a value towards plus infinity - * - * ceil(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ - math.ceil = function ceil(x) { - if (arguments.length != 1) { - throw new util.error.ArgumentsError('ceil', arguments.length, 1); - } - - if (isNumber(x)) { - return Math.ceil(x); - } - - if (isComplex(x)) { - return Complex.create ( - Math.ceil(x.re), - Math.ceil(x.im) - ); - } - - if (isCollection(x)) { - return collection.map(x, ceil); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return ceil(x.valueOf()); - } - - throw new util.error.UnsupportedTypeError('ceil', x); - }; -}; diff --git a/src/function/arithmetic/cube.js b/src/function/arithmetic/cube.js deleted file mode 100644 index 8bccce8f7..000000000 --- a/src/function/arithmetic/cube.js +++ /dev/null @@ -1,46 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Complex = require('../../type/Complex.js'), - collection = require('../../type/collection.js'), - - isNumber = util.number.isNumber, - isComplex = Complex.isComplex, - isCollection = collection.isCollection; - - /** - * Compute the cube of a value - * - * x .* x .* x - * cube(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ - math.cube = function cube(x) { - if (arguments.length != 1) { - throw new util.error.ArgumentsError('cube', arguments.length, 1); - } - - if (isNumber(x)) { - return x * x * x; - } - - if (isComplex(x)) { - return math.multiply(math.multiply(x, x), x); - } - - if (isCollection(x)) { - return collection.map(x, cube); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return cube(x.valueOf()); - } - - throw new util.error.UnsupportedTypeError('cube', x); - }; -}; diff --git a/src/function/arithmetic/divide.js b/src/function/arithmetic/divide.js deleted file mode 100644 index 66b5ef11f..000000000 --- a/src/function/arithmetic/divide.js +++ /dev/null @@ -1,109 +0,0 @@ -module.exports = function(math) { - var util = require('../../util/index.js'), - - Complex = require('../../type/Complex.js'), - Matrix = require('../../type/Matrix.js'), - Unit = require('../../type/Unit.js'), - collection = require('../../type/collection.js'), - - isNumber = util.number.isNumber, - isComplex = Complex.isComplex, - isUnit = Unit.isUnit, - isCollection = collection.isCollection; - - /** - * Divide two values. - * - * x / y - * divide(x, y) - * - * @param {Number | Complex | Unit | Array | Matrix} x - * @param {Number | Complex} y - * @return {Number | Complex | Unit | Array | Matrix} res - */ - math.divide = function divide(x, y) { - if (arguments.length != 2) { - throw new util.error.ArgumentsError('divide', arguments.length, 2); - } - - if (isNumber(x)) { - if (isNumber(y)) { - // number / number - return x / y; - } - else if (isComplex(y)) { - // number / complex - return _divideComplex(new Complex(x, 0), y); - } - } - - if (isComplex(x)) { - if (isNumber(y)) { - // complex / number - return _divideComplex(x, new Complex(y, 0)); - } - else if (isComplex(y)) { - // complex / complex - return _divideComplex(x, y); - } - } - - if (isUnit(x)) { - if (isNumber(y)) { - var res = x.clone(); - res.value /= y; - return res; - } - } - - if (isCollection(x)) { - if (isCollection(y)) { - // TODO: implement matrix right division using pseudo inverse - // http://www.mathworks.nl/help/matlab/ref/mrdivide.html - // http://www.gnu.org/software/octave/doc/interpreter/Arithmetic-Ops.html - // http://stackoverflow.com/questions/12263932/how-does-gnu-octave-matrix-division-work-getting-unexpected-behaviour - return math.multiply(x, math.inv(y)); - } - else { - // matrix / scalar - return collection.map2(x, y, divide); - } - } - - if (isCollection(y)) { - // TODO: implement matrix right division using pseudo inverse - return math.multiply(x, math.inv(y)); - } - - if (x.valueOf() !== x || y.valueOf() !== y) { - // fallback on the objects primitive value - return divide(x.valueOf(), y.valueOf()); - } - - throw new util.error.UnsupportedTypeError('divide', x, y); - }; - - /** - * Divide two complex numbers. x / y or divide(x, y) - * @param {Complex} x - * @param {Complex} y - * @return {Complex} res - * @private - */ - function _divideComplex (x, y) { - var den = y.re * y.re + y.im * y.im; - if (den != 0) { - return Complex.create( - (x.re * y.re + x.im * y.im) / den, - (x.im * y.re - x.re * y.im) / den - ); - } - else { - // both y.re and y.im are zero - return Complex.create( - (x.re != 0) ? (x.re / 0) : 0, - (x.im != 0) ? (x.im / 0) : 0 - ); - } - } -}; diff --git a/src/function/arithmetic/edivide.js b/src/function/arithmetic/edivide.js deleted file mode 100644 index dcd763b62..000000000 --- a/src/function/arithmetic/edivide.js +++ /dev/null @@ -1,22 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - collection = require('../../type/collection.js'); - - /** - * Divide two values element wise. - * - * x ./ y - * edivide(x, y) - * - * @param {Number | Complex | Unit | Array | Matrix} x - * @param {Number | Complex | Unit | Array | Matrix} y - * @return {Number | Complex | Unit | Array | Matrix} res - */ - math.edivide = function edivide(x, y) { - if (arguments.length != 2) { - throw new util.error.ArgumentsError('edivide', arguments.length, 2); - } - - return collection.deepMap2(x, y, math.divide); - }; -}; diff --git a/src/function/arithmetic/emultiply.js b/src/function/arithmetic/emultiply.js deleted file mode 100644 index 559fa65e9..000000000 --- a/src/function/arithmetic/emultiply.js +++ /dev/null @@ -1,22 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - collection = require('../../type/collection.js'); - - /** - * Multiply two values element wise. - * - * x .* y - * emultiply(x, y) - * - * @param {Number | Complex | Unit | Array | Matrix} x - * @param {Number | Complex | Unit | Array | Matrix} y - * @return {Number | Complex | Unit | Array | Matrix} res - */ - math.emultiply = function emultiply(x, y) { - if (arguments.length != 2) { - throw new util.error.ArgumentsError('emultiply', arguments.length, 2); - } - - return collection.deepMap2(x, y, math.multiply); - }; -}; diff --git a/src/function/arithmetic/epow.js b/src/function/arithmetic/epow.js deleted file mode 100644 index 59990bfc3..000000000 --- a/src/function/arithmetic/epow.js +++ /dev/null @@ -1,22 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - collection = require('../../type/collection.js'); - - /** - * Calculates the power of x to y element wise - * - * x .^ y - * epow(x, y) - * - * @param {Number | Complex | Unit | Array | Matrix} x - * @param {Number | Complex | Unit | Array | Matrix} y - * @return {Number | Complex | Unit | Array | Matrix} res - */ - math.epow = function epow(x, y) { - if (arguments.length != 2) { - throw new util.error.ArgumentsError('epow', arguments.length, 2); - } - - return collection.deepMap2(x, y, math.pow); - }; -}; diff --git a/src/function/arithmetic/equal.js b/src/function/arithmetic/equal.js deleted file mode 100644 index a6c152d35..000000000 --- a/src/function/arithmetic/equal.js +++ /dev/null @@ -1,71 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Complex = require('../../type/Complex.js'), - Unit = require('../../type/Unit.js'), - collection = require('../../type/collection.js'), - - isNumber = util.number.isNumber, - isString = util.string.isString, - isComplex = Complex.isComplex, - isUnit = Unit.isUnit, - isCollection = collection.isCollection; - - /** - * Check if value x equals y, - * - * x == y - * equal(x, y) - * - * For matrices, the function is evaluated element wise. - * In case of complex numbers, x.re must equal y.re, and x.im must equal y.im. - * - * @param {Number | Complex | Unit | String | Array | Matrix} x - * @param {Number | Complex | Unit | String | Array | Matrix} y - * @return {Boolean | Array | Matrix} res - */ - math.equal = function equal(x, y) { - if (arguments.length != 2) { - throw new util.error.ArgumentsError('equal', arguments.length, 2); - } - - if (isNumber(x)) { - if (isNumber(y)) { - return x == y; - } - else if (isComplex(y)) { - return (x == y.re) && (y.im == 0); - } - } - if (isComplex(x)) { - if (isNumber(y)) { - return (x.re == y) && (x.im == 0); - } - else if (isComplex(y)) { - return (x.re == y.re) && (x.im == y.im); - } - } - - if ((isUnit(x)) && (isUnit(y))) { - if (!x.equalBase(y)) { - throw new Error('Cannot compare units with different base'); - } - return x.value == y.value; - } - - if (isString(x) || isString(y)) { - return x == y; - } - - if (isCollection(x) || isCollection(y)) { - return collection.map2(x, y, equal); - } - - if (x.valueOf() !== x || y.valueOf() !== y) { - // fallback on the objects primitive values - return equal(x.valueOf(), y.valueOf()); - } - - throw new util.error.UnsupportedTypeError('equal', x, y); - }; -}; diff --git a/src/function/arithmetic/exp.js b/src/function/arithmetic/exp.js deleted file mode 100644 index 9bf1a6a69..000000000 --- a/src/function/arithmetic/exp.js +++ /dev/null @@ -1,49 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Complex = require('../../type/Complex.js'), - Matrix = require('../../type/Matrix.js'), - collection = require('../../type/collection.js'), - - isNumber = util.number.isNumber, - isComplex = Complex.isComplex, - isCollection = collection.isCollection; - - /** - * Calculate the exponent of a value - * - * exp(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ - math.exp = function exp (x) { - if (arguments.length != 1) { - throw new util.error.ArgumentsError('exp', arguments.length, 1); - } - - if (isNumber(x)) { - return Math.exp(x); - } - if (isComplex(x)) { - var r = Math.exp(x.re); - return Complex.create( - r * Math.cos(x.im), - r * Math.sin(x.im) - ); - } - - if (isCollection(x)) { - return collection.map(x, exp); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return exp(x.valueOf()); - } - - throw new util.error.UnsupportedTypeError('exp', x); - }; -}; diff --git a/src/function/arithmetic/fix.js b/src/function/arithmetic/fix.js deleted file mode 100644 index c586aeaa5..000000000 --- a/src/function/arithmetic/fix.js +++ /dev/null @@ -1,48 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Complex = require('../../type/Complex.js'), - collection = require('../../type/collection.js'), - - isNumber = util.number.isNumber, - isComplex = Complex.isComplex, - isCollection = collection.isCollection; - - /** - * Round a value towards zero - * - * fix(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ - math.fix = function fix(x) { - if (arguments.length != 1) { - throw new util.error.ArgumentsError('fix', arguments.length, 1); - } - - if (isNumber(x)) { - return (x > 0) ? Math.floor(x) : Math.ceil(x); - } - - if (isComplex(x)) { - return Complex.create( - (x.re > 0) ? Math.floor(x.re) : Math.ceil(x.re), - (x.im > 0) ? Math.floor(x.im) : Math.ceil(x.im) - ); - } - - if (isCollection(x)) { - return collection.map(x, fix); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return fix(x.valueOf()); - } - - throw new util.error.UnsupportedTypeError('fix', x); - }; -}; diff --git a/src/function/arithmetic/floor.js b/src/function/arithmetic/floor.js deleted file mode 100644 index 92281c133..000000000 --- a/src/function/arithmetic/floor.js +++ /dev/null @@ -1,48 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Complex = require('../../type/Complex.js'), - collection = require('../../type/collection.js'), - - isNumber = util.number.isNumber, - isComplex = Complex.isComplex, - isCollection = collection.isCollection; - - /** - * Round a value towards minus infinity - * - * floor(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ - math.floor = function floor(x) { - if (arguments.length != 1) { - throw new util.error.ArgumentsError('floor', arguments.length, 1); - } - - if (isNumber(x)) { - return Math.floor(x); - } - - if (isComplex(x)) { - return Complex.create ( - Math.floor(x.re), - Math.floor(x.im) - ); - } - - if (isCollection(x)) { - return collection.map(x, floor); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return floor(x.valueOf()); - } - - throw new util.error.UnsupportedTypeError('floor', x); - }; -}; diff --git a/src/function/arithmetic/gcd.js b/src/function/arithmetic/gcd.js deleted file mode 100644 index 90093cb85..000000000 --- a/src/function/arithmetic/gcd.js +++ /dev/null @@ -1,66 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - collection = require('../../type/collection.js'), - - isNumber = util.number.isNumber, - isInteger = util.number.isInteger, - isCollection = collection.isCollection; - - /** - * Calculate the greatest common divisor for two or more values or arrays. - * - * gcd(a, b) - * gcd(a, b, c, ...) - * - * For matrices, the function is evaluated element wise. - * - * @param {... Number | Array | Matrix} args two or more integer numbers - * @return {Number | Array | Matrix} greatest common divisor - */ - math.gcd = function gcd(args) { - var a = arguments[0], - b = arguments[1], - t; - - if (arguments.length == 2) { - // two arguments - if (isNumber(a) && isNumber(b)) { - if (!isInteger(a) || !isInteger(b)) { - throw new Error('Parameters in function gcd must be integer numbers'); - } - - // http://en.wikipedia.org/wiki/Euclidean_algorithm - while (b != 0) { - t = b; - b = a % t; - a = t; - } - return Math.abs(a); - } - - // evaluate gcd element wise - if (isCollection(a) || isCollection(b)) { - return collection.map2(a, b, gcd); - } - - if (a.valueOf() !== a || b.valueOf() !== b) { - // fallback on the objects primitive value - return gcd(a.valueOf(), b.valueOf()); - } - - throw new util.error.UnsupportedTypeError('gcd', a, b); - } - - if (arguments.length > 2) { - // multiple arguments. Evaluate them iteratively - for (var i = 1; i < arguments.length; i++) { - a = gcd(a, arguments[i]); - } - return a; - } - - // zero or one argument - throw new SyntaxError('Function gcd expects two or more arguments'); - }; -}; diff --git a/src/function/arithmetic/larger.js b/src/function/arithmetic/larger.js deleted file mode 100644 index 6c478059d..000000000 --- a/src/function/arithmetic/larger.js +++ /dev/null @@ -1,71 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Complex = require('../../type/Complex.js'), - Unit = require('../../type/Unit.js'), - collection = require('../../type/collection.js'), - - isNumber = util.number.isNumber, - isString = util.string.isString, - isComplex = Complex.isComplex, - isUnit = Unit.isUnit, - isCollection = collection.isCollection; - - /** - * Check if value x is larger y - * - * x > y - * larger(x, y) - * - * For matrices, the function is evaluated element wise. - * In case of complex numbers, the absolute values of a and b are compared. - * - * @param {Number | Complex | Unit | String | Array | Matrix} x - * @param {Number | Complex | Unit | String | Array | Matrix} y - * @return {Boolean | Array | Matrix} res - */ - math.larger = function larger(x, y) { - if (arguments.length != 2) { - throw new util.error.ArgumentsError('larger', arguments.length, 2); - } - - if (isNumber(x)) { - if (isNumber(y)) { - return x > y; - } - else if (isComplex(y)) { - return x > math.abs(y); - } - } - if (isComplex(x)) { - if (isNumber(y)) { - return math.abs(x) > y; - } - else if (isComplex(y)) { - return math.abs(x) > math.abs(y); - } - } - - if ((isUnit(x)) && (isUnit(y))) { - if (!x.equalBase(y)) { - throw new Error('Cannot compare units with different base'); - } - return x.value > y.value; - } - - if (isString(x) || isString(y)) { - return x > y; - } - - if (isCollection(x) || isCollection(y)) { - return collection.map2(x, y, larger); - } - - if (x.valueOf() !== x || y.valueOf() !== y) { - // fallback on the objects primitive values - return larger(x.valueOf(), y.valueOf()); - } - - throw new util.error.UnsupportedTypeError('larger', x, y); - }; -}; diff --git a/src/function/arithmetic/largereq.js b/src/function/arithmetic/largereq.js deleted file mode 100644 index da721adc5..000000000 --- a/src/function/arithmetic/largereq.js +++ /dev/null @@ -1,71 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Complex = require('../../type/Complex.js'), - Unit = require('../../type/Unit.js'), - collection = require('../../type/collection.js'), - - isNumber = util.number.isNumber, - isString = util.string.isString, - isComplex = Complex.isComplex, - isUnit = Unit.isUnit, - isCollection = collection.isCollection; - - /** - * Check if value x is larger or equal to y - * - * x >= y - * largereq(x, y) - * - * For matrices, the function is evaluated element wise. - * In case of complex numbers, the absolute values of a and b are compared. - * - * @param {Number | Complex | Unit | String | Array | Matrix} x - * @param {Number | Complex | Unit | String | Array | Matrix} y - * @return {Boolean | Array | Matrix} res - */ - math.largereq = function largereq(x, y) { - if (arguments.length != 2) { - throw new util.error.ArgumentsError('largereq', arguments.length, 2); - } - - if (isNumber(x)) { - if (isNumber(y)) { - return x >= y; - } - else if (isComplex(y)) { - return x >= math.abs(y); - } - } - if (isComplex(x)) { - if (isNumber(y)) { - return math.abs(x) >= y; - } - else if (isComplex(y)) { - return math.abs(x) >= math.abs(y); - } - } - - if ((isUnit(x)) && (isUnit(y))) { - if (!x.equalBase(y)) { - throw new Error('Cannot compare units with different base'); - } - return x.value >= y.value; - } - - if (isString(x) || isString(y)) { - return x >= y; - } - - if (isCollection(x) || isCollection(y)) { - return collection.map2(x, y, largereq); - } - - if (x.valueOf() !== x || y.valueOf() !== y) { - // fallback on the objects primitive values - return largereq(x.valueOf(), y.valueOf()); - } - - throw new util.error.UnsupportedTypeError('largereq', x, y); - }; -}; diff --git a/src/function/arithmetic/lcm.js b/src/function/arithmetic/lcm.js deleted file mode 100644 index ad885821d..000000000 --- a/src/function/arithmetic/lcm.js +++ /dev/null @@ -1,71 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - collection = require('../../type/collection.js'), - - isNumber = util.number.isNumber, - isInteger = util.number.isInteger, - isCollection = collection.isCollection; - - /** - * Calculate the least common multiple for two or more values or arrays. - * - * lcm(a, b) - * lcm(a, b, c, ...) - * - * lcm is defined as: - * lcm(a, b) = abs(a * b) / gcd(a, b) - * - * For matrices, the function is evaluated element wise. - * - * @param {... Number | Array | Matrix} args two or more integer numbers - * @return {Number | Array | Matrix} least common multiple - */ - math.lcm = function lcm(args) { - var a = arguments[0], - b = arguments[1], - t; - - if (arguments.length == 2) { - // two arguments - if (isNumber(a) && isNumber(b)) { - if (!isInteger(a) || !isInteger(b)) { - throw new Error('Parameters in function lcm must be integer numbers'); - } - - // http://en.wikipedia.org/wiki/Euclidean_algorithm - // evaluate gcd here inline to reduce overhead - var prod = a * b; - while (b != 0) { - t = b; - b = a % t; - a = t; - } - return Math.abs(prod / a); - } - - // evaluate lcm element wise - if (isCollection(a) || isCollection(b)) { - return collection.map2(a, b, lcm); - } - - if (a.valueOf() !== a || b.valueOf() !== b) { - // fallback on the objects primitive value - return lcm(a.valueOf(), b.valueOf()); - } - - throw new util.error.UnsupportedTypeError('lcm', a, b); - } - - if (arguments.length > 2) { - // multiple arguments. Evaluate them iteratively - for (var i = 1; i < arguments.length; i++) { - a = lcm(a, arguments[i]); - } - return a; - } - - // zero or one argument - throw new SyntaxError('Function lcm expects two or more arguments'); - }; -}; diff --git a/src/function/arithmetic/log.js b/src/function/arithmetic/log.js deleted file mode 100644 index 0f9c0e2ab..000000000 --- a/src/function/arithmetic/log.js +++ /dev/null @@ -1,63 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Complex = require('../../type/Complex.js'), - collection = require('../../type/collection.js'), - - isNumber = util.number.isNumber, - isComplex = Complex.isComplex, - isCollection = collection.isCollection; - - /** - * Calculate the logarithm of a value - * - * log(x) - * log(x, base) - * - * base is optional. If not provided, the natural logarithm of x is calculated. - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @param {Number | Complex} [base] - * @return {Number | Complex | Array | Matrix} res - */ - math.log = function log(x, base) { - if (arguments.length == 1) { - // calculate natural logarithm, log(x) - if (isNumber(x)) { - if (x >= 0) { - return Math.log(x); - } - else { - // negative value -> complex value computation - return log(new Complex(x, 0)); - } - } - - if (isComplex(x)) { - return Complex.create ( - Math.log(Math.sqrt(x.re * x.re + x.im * x.im)), - Math.atan2(x.im, x.re) - ); - } - - if (isCollection(x)) { - return collection.map(x, log); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive values - return log(x.valueOf()); - } - - throw new util.error.UnsupportedTypeError('log', x); - } - else if (arguments.length == 2) { - // calculate logarithm for a specified base, log(x, base) - return math.divide(log(x), log(base)); - } - else { - throw new util.error.ArgumentsError('log', arguments.length, 1, 2); - } - }; -}; diff --git a/src/function/arithmetic/log10.js b/src/function/arithmetic/log10.js deleted file mode 100644 index c4a7a8633..000000000 --- a/src/function/arithmetic/log10.js +++ /dev/null @@ -1,54 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Complex = require('../../type/Complex.js'), - collection = require('../../type/collection.js'), - - isNumber = util.number.isNumber, - isComplex = Complex.isComplex, - isCollection = collection.isCollection; - - /** - * Calculate the 10-base logarithm of a value - * - * log10(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ - math.log10 = function log10(x) { - if (arguments.length != 1) { - throw new util.error.ArgumentsError('log10', arguments.length, 1); - } - - if (isNumber(x)) { - if (x >= 0) { - return Math.log(x) / Math.LN10; - } - else { - // negative value -> complex value computation - return log10(new Complex(x, 0)); - } - } - - if (isComplex(x)) { - return Complex.create ( - Math.log(Math.sqrt(x.re * x.re + x.im * x.im)) / Math.LN10, - Math.atan2(x.im, x.re) / Math.LN10 - ); - } - - if (isCollection(x)) { - return collection.map(x, log10); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return log10(x.valueOf()); - } - - throw new util.error.UnsupportedTypeError('log10', x); - }; -}; diff --git a/src/function/arithmetic/mod.js b/src/function/arithmetic/mod.js deleted file mode 100644 index 7cd64a090..000000000 --- a/src/function/arithmetic/mod.js +++ /dev/null @@ -1,74 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - collection = require('../../type/collection.js'), - - isNumber = util.number.isNumber, - isCollection = collection.isCollection; - - /** - * Calculates the modulus, the remainder of an integer division. - * - * x % y - * mod(x, y) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Array | Matrix} x - * @param {Number | Array | Matrix} y - * @return {Number | Array | Matrix} res - */ - math.mod = function mod(x, y) { - if (arguments.length != 2) { - throw new util.error.ArgumentsError('mod', arguments.length, 2); - } - - // see http://functions.wolfram.com/IntegerFunctions/Mod/ - - if (isNumber(x) && isNumber(y)) { - // number % number - return _mod(x, y); - } - - // TODO: implement mod for complex values - - if (isCollection(x) || isCollection(y)) { - return collection.map2(x, y, mod); - } - - if (x.valueOf() !== x || y.valueOf() !== y) { - // fallback on the objects primitive values - return mod(x.valueOf(), y.valueOf()); - } - - throw new util.error.UnsupportedTypeError('mod', x, y); - }; - - /** - * Calculate the modulus of two numbers - * @param {Number} x - * @param {Number} y - * @returns {number} res - * @private - */ - function _mod(x, y) { - if (y > 0) { - if (x > 0) { - return x % y; - } - else if (x == 0) { - return 0; - } - else { // x < 0 - return x - y * Math.floor(x / y); - } - } - else if (y == 0) { - return x; - } - else { // y < 0 - // TODO: implement mod for a negative divisor - throw new Error('Cannot calculate mod for a negative divisor'); - } - } -}; diff --git a/src/function/arithmetic/multiply.js b/src/function/arithmetic/multiply.js deleted file mode 100644 index 2fc270cf4..000000000 --- a/src/function/arithmetic/multiply.js +++ /dev/null @@ -1,210 +0,0 @@ -module.exports = function(math) { - var util = require('../../util/index.js'), - - Complex = require('../../type/Complex.js'), - Matrix = require('../../type/Matrix.js'), - Unit = require('../../type/Unit.js'), - collection = require('../../type/collection.js'), - - array = util.array, - isNumber = util.number.isNumber, - isComplex = Complex.isComplex, - isArray = Array.isArray, - isUnit = Unit.isUnit; - - /** - * Multiply two values. - * - * x * y - * multiply(x, y) - * - * @param {Number | Complex | Unit | Array | Matrix} x - * @param {Number | Complex | Unit | Array | Matrix} y - * @return {Number | Complex | Unit | Array | Matrix} res - */ - math.multiply = function multiply(x, y) { - if (arguments.length != 2) { - throw new util.error.ArgumentsError('multiply', arguments.length, 2); - } - - if (isNumber(x)) { - if (isNumber(y)) { - // number * number - return x * y; - } - else if (isComplex(y)) { - // number * complex - return _multiplyComplex (new Complex(x, 0), y); - } - else if (isUnit(y)) { - res = y.clone(); - res.value *= x; - return res; - } - } - else if (isComplex(x)) { - if (isNumber(y)) { - // complex * number - return _multiplyComplex (x, new Complex(y, 0)); - } - else if (isComplex(y)) { - // complex * complex - return _multiplyComplex (x, y); - } - } - else if (isUnit(x)) { - if (isNumber(y)) { - res = x.clone(); - res.value *= y; - return res; - } - } - else if (isArray(x)) { - if (isArray(y)) { - // matrix * matrix - var sizeX = array.size(x); - var sizeY = array.size(y); - - if (sizeX.length != 2) { - throw new Error('Can only multiply a 2 dimensional matrix ' + - '(A has ' + sizeX.length + ' dimensions)'); - } - if (sizeY.length != 2) { - throw new Error('Can only multiply a 2 dimensional matrix ' + - '(B has ' + sizeY.length + ' dimensions)'); - } - if (sizeX[1] != sizeY[0]) { - throw new RangeError('Dimensions mismatch in multiplication. ' + - 'Columns of A must match rows of B ' + - '(A is ' + sizeX[0] + 'x' + sizeX[1] + - ', B is ' + sizeY[0] + 'x' + sizeY[1] + ', ' + - sizeY[1] + ' != ' + sizeY[0] + ')'); - } - - // TODO: performance of matrix multiplication can be improved - var res = [], - rows = sizeX[0], - cols = sizeY[1], - num = sizeX[1]; - for (var r = 0; r < rows; r++) { - res[r] = []; - for (var c = 0; c < cols; c++) { - var result = null; - for (var n = 0; n < num; n++) { - var p = multiply(x[r][n], y[n][c]); - result = (result == null) ? p : math.add(result, p); - } - res[r][c] = result; - } - } - - return res; - } - else if (y instanceof Matrix) { - return new Matrix(multiply(x.valueOf(), y.valueOf())); - } - else { - // matrix * scalar - return collection.map2(x, y, multiply); - } - } - else if (x instanceof Matrix) { - return new Matrix(multiply(x.valueOf(), y.valueOf())); - } - - if (isArray(y)) { - // scalar * matrix - return collection.map2(x, y, multiply); - } - else if (y instanceof Matrix) { - return new Matrix(multiply(x.valueOf(), y.valueOf())); - } - - if (x.valueOf() !== x || y.valueOf() !== y) { - // fallback on the objects primitive values - return multiply(x.valueOf(), y.valueOf()); - } - - throw new util.error.UnsupportedTypeError('multiply', x, y); - }; - - /** - * Multiply two complex numbers. x * y or multiply(x, y) - * @param {Complex} x - * @param {Complex} y - * @return {Complex | Number} res - * @private - */ - function _multiplyComplex (x, y) { - // Note: we test whether x or y are pure real or pure complex, - // to prevent unnecessary NaN values. For example, Infinity*i should - // result in Infinity*i, and not in NaN+Infinity*i - - if (x.im == 0) { - // x is pure real - if (y.im == 0) { - // y is pure real - return x.re * y.re; - } - else if (y.re == 0) { - // y is pure complex - return new Complex( - 0, - x.re * y.im - ); - } - else { - // y has a real and complex part - return new Complex( - x.re * y.re, - x.re * y.im - ); - } - } - else if (x.re == 0) { - // x is pure complex - if (y.im == 0) { - // y is pure real - return new Complex( - 0, - x.im * y.re - ); - } - else if (y.re == 0) { - // y is pure complex - return -x.im * y.im; - } - else { - // y has a real and complex part - return new Complex( - -x.im * y.im, - x.im * y.re - ); - } - } - else { - // x has a real and complex part - if (y.im == 0) { - // y is pure real - return new Complex( - x.re * y.re, - x.im * y.re - ); - } - else if (y.re == 0) { - // y is pure complex - return new Complex( - -x.im * y.im, - x.re * y.im - ); - } - else { - // y has a real and complex part - return new Complex( - x.re * y.re - x.im * y.im, - x.re * y.im + x.im * y.re - ); - } - } - } -}; diff --git a/src/function/arithmetic/pow.js b/src/function/arithmetic/pow.js deleted file mode 100644 index d045d19b4..000000000 --- a/src/function/arithmetic/pow.js +++ /dev/null @@ -1,105 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Complex = require('../../type/Complex.js'), - Matrix = require('../../type/Matrix.js'), - - array = util.array, - isNumber = util.number.isNumber, - isArray = Array.isArray, - isInteger = util.number.isInteger, - isComplex = Complex.isComplex; - - /** - * Calculates the power of x to y - * - * x ^ y - * pow(x, y) - * - * @param {Number | Complex | Array | Matrix} x - * @param {Number | Complex} y - * @return {Number | Complex | Array | Matrix} res - */ - math.pow = function pow(x, y) { - if (arguments.length != 2) { - throw new util.error.ArgumentsError('pow', arguments.length, 2); - } - - if (isNumber(x)) { - if (isNumber(y)) { - if (isInteger(y) || x >= 0) { - // real value computation - return Math.pow(x, y); - } - else { - return powComplex(new Complex(x, 0), new Complex(y, 0)); - } - } - else if (isComplex(y)) { - return powComplex(new Complex(x, 0), y); - } - } - else if (isComplex(x)) { - if (isNumber(y)) { - return powComplex(x, new Complex(y, 0)); - } - else if (isComplex(y)) { - return powComplex(x, y); - } - } - else if (isArray(x)) { - if (!isNumber(y) || !isInteger(y) || y < 0) { - throw new TypeError('For A^b, b must be a positive integer ' + - '(value is ' + y + ')'); - } - // verify that A is a 2 dimensional square matrix - var s = array.size(x); - if (s.length != 2) { - throw new Error('For A^b, A must be 2 dimensional ' + - '(A has ' + s.length + ' dimensions)'); - } - if (s[0] != s[1]) { - throw new Error('For A^b, A must be square ' + - '(size is ' + s[0] + 'x' + s[1] + ')'); - } - - if (y == 0) { - // return the identity matrix - return math.eye(s[0]); - } - else { - // value > 0 - var res = x; - for (var i = 1; i < y; i++) { - res = math.multiply(x, res); - } - return res; - } - } - else if (x instanceof Matrix) { - return new Matrix(pow(x.valueOf(), y)); - } - - if (x.valueOf() !== x || y.valueOf() !== y) { - // fallback on the objects primitive values - return pow(x.valueOf(), y.valueOf()); - } - - throw new util.error.UnsupportedTypeError('pow', x, y); - }; - - /** - * Calculates the power of x to y, x^y, for two complex numbers. - * @param {Complex} x - * @param {Complex} y - * @return {Complex} res - * @private - */ - function powComplex (x, y) { - // complex computation - // x^y = exp(log(x)*y) = exp((abs(x)+i*arg(x))*y) - var temp1 = math.log(x); - var temp2 = math.multiply(temp1, y); - return math.exp(temp2); - } -}; diff --git a/src/function/arithmetic/round.js b/src/function/arithmetic/round.js deleted file mode 100644 index aba4759c0..000000000 --- a/src/function/arithmetic/round.js +++ /dev/null @@ -1,104 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Complex = require('../../type/Complex.js'), - collection = require('../../type/collection.js'), - - isNumber = util.number.isNumber, - isComplex = Complex.isComplex, - isCollection = collection.isCollection; - - /** - * Round a value towards the nearest integer - * - * round(x) - * round(x, n) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @param {Number | Array} [n] number of decimals (by default n=0) - * @return {Number | Complex | Array | Matrix} res - */ - math.round = function round(x, n) { - if (arguments.length != 1 && arguments.length != 2) { - throw new util.error.ArgumentsError('round', arguments.length, 1, 2); - } - - if (n == undefined) { - // round (x) - if (isNumber(x)) { - return Math.round(x); - } - - if (isComplex(x)) { - return Complex.create ( - Math.round(x.re), - Math.round(x.im) - ); - } - - if (isCollection(x)) { - return collection.map(x, round); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return round(x.valueOf()); - } - - throw new util.error.UnsupportedTypeError('round', x); - } - else { - // round (x, n) - if (!isNumber(n)) { - throw new TypeError('Number of decimals in function round must be an integer'); - } - if (n !== Math.round(n)) { - throw new TypeError('Number of decimals in function round must be integer'); - } - if (n < 0 || n > 9) { - throw new Error ('Number of decimals in function round must be in te range of 0-9'); - } - - if (isNumber(x)) { - return roundNumber(x, n); - } - - if (isComplex(x)) { - return Complex.create ( - roundNumber(x.re, n), - roundNumber(x.im, n) - ); - } - - if (isCollection(x) || isCollection(n)) { - return collection.map2(x, n, round); - } - - if (x.valueOf() !== x || n.valueOf() !== n) { - // fallback on the objects primitive values - return round(x.valueOf(), n.valueOf()); - } - - throw new util.error.UnsupportedTypeError('round', x, n); - } - }; - - /** - * round a number to the given number of decimals, or to zero if decimals is - * not provided - * @param {Number} value - * @param {Number} [decimals] number of decimals, between 0 and 15 (0 by default) - * @return {Number} roundedValue - */ - function roundNumber (value, decimals) { - if (decimals) { - var p = Math.pow(10, decimals); - return Math.round(value * p) / p; - } - else { - return Math.round(value); - } - } -}; diff --git a/src/function/arithmetic/sign.js b/src/function/arithmetic/sign.js deleted file mode 100644 index d2630eb72..000000000 --- a/src/function/arithmetic/sign.js +++ /dev/null @@ -1,48 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Complex = require('../../type/Complex.js'), - collection = require('../../type/collection.js'), - - number = util.number, - isNumber = util.number.isNumber, - isComplex = Complex.isComplex, - isCollection = collection.isCollection; - - /** - * Compute the sign of a value. - * - * sign(x) - * - * The sign of a value x is 1 when x > 1, -1 when x < 0, and 0 when x == 0 - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ - math.sign = function sign(x) { - if (arguments.length != 1) { - throw new util.error.ArgumentsError('sign', arguments.length, 1); - } - - if (isNumber(x)) { - return number.sign(x); - } - - if (isComplex(x)) { - var abs = Math.sqrt(x.re * x.re + x.im * x.im); - return Complex.create(x.re / abs, x.im / abs); - } - - if (isCollection(x)) { - return collection.map(x, sign); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return sign(x.valueOf()); - } - - throw new util.error.UnsupportedTypeError('sign', x); - }; -}; diff --git a/src/function/arithmetic/smaller.js b/src/function/arithmetic/smaller.js deleted file mode 100644 index 76143cf70..000000000 --- a/src/function/arithmetic/smaller.js +++ /dev/null @@ -1,71 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Complex = require('../../type/Complex.js'), - Unit = require('../../type/Unit.js'), - collection = require('../../type/collection.js'), - - isNumber = util.number.isNumber, - isString = util.string.isString, - isComplex = Complex.isComplex, - isUnit = Unit.isUnit, - isCollection = collection.isCollection; - - /** - * Check if value x is smaller y - * - * x < y - * smaller(x, y) - * - * For matrices, the function is evaluated element wise. - * In case of complex numbers, the absolute values of a and b are compared. - * - * @param {Number | Complex | Unit | String | Array | Matrix} x - * @param {Number | Complex | Unit | String | Array | Matrix} y - * @return {Boolean | Array | Matrix} res - */ - math.smaller = function smaller(x, y) { - if (arguments.length != 2) { - throw new util.error.ArgumentsError('smaller', arguments.length, 2); - } - - if (isNumber(x)) { - if (isNumber(y)) { - return x < y; - } - else if (isComplex(y)) { - return x < math.abs(y); - } - } - if (isComplex(x)) { - if (isNumber(y)) { - return math.abs(x) < y; - } - else if (isComplex(y)) { - return math.abs(x) < math.abs(y); - } - } - - if ((isUnit(x)) && (isUnit(y))) { - if (!x.equalBase(y)) { - throw new Error('Cannot compare units with different base'); - } - return x.value < y.value; - } - - if (isString(x) || isString(y)) { - return x < y; - } - - if (isCollection(x) || isCollection(y)) { - return collection.map2(x, y, smaller); - } - - if (x.valueOf() !== x || y.valueOf() !== y) { - // fallback on the objects primitive values - return smaller(x.valueOf(), y.valueOf()); - } - - throw new util.error.UnsupportedTypeError('smaller', x, y); - }; -}; diff --git a/src/function/arithmetic/smallereq.js b/src/function/arithmetic/smallereq.js deleted file mode 100644 index c45f3e6ce..000000000 --- a/src/function/arithmetic/smallereq.js +++ /dev/null @@ -1,71 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Complex = require('../../type/Complex.js'), - Unit = require('../../type/Unit.js'), - collection = require('../../type/collection.js'), - - isNumber = util.number.isNumber, - isString = util.string.isString, - isComplex = Complex.isComplex, - isUnit = Unit.isUnit, - isCollection = collection.isCollection; - - /** - * Check if value a is smaller or equal to b - * - * a <= b - * smallereq(a, b) - * - * For matrices, the function is evaluated element wise. - * In case of complex numbers, the absolute values of a and b are compared. - * - * @param {Number | Complex | Unit | String | Array | Matrix} x - * @param {Number | Complex | Unit | String | Array | Matrix} y - * @return {Boolean | Array | Matrix} res - */ - math.smallereq = function smallereq(x, y) { - if (arguments.length != 2) { - throw new util.error.ArgumentsError('smallereq', arguments.length, 2); - } - - if (isNumber(x)) { - if (isNumber(y)) { - return x <= y; - } - else if (isComplex(y)) { - return x <= math.abs(y); - } - } - if (isComplex(x)) { - if (isNumber(y)) { - return math.abs(x) <= y; - } - else if (isComplex(y)) { - return math.abs(x) <= math.abs(y); - } - } - - if ((isUnit(x)) && (isUnit(y))) { - if (!x.equalBase(y)) { - throw new Error('Cannot compare units with different base'); - } - return x.value <= y.value; - } - - if (isString(x) || isString(y)) { - return x <= y; - } - - if (isCollection(x) || isCollection(y)) { - return collection.map2(x, y, smallereq); - } - - if (x.valueOf() !== x || y.valueOf() !== y) { - // fallback on the objects primitive values - return smallereq(x.valueOf(), y.valueOf()); - } - - throw new util.error.UnsupportedTypeError('smallereq', x, y); - }; -}; diff --git a/src/function/arithmetic/sqrt.js b/src/function/arithmetic/sqrt.js deleted file mode 100644 index b3448fcae..000000000 --- a/src/function/arithmetic/sqrt.js +++ /dev/null @@ -1,62 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Complex = require('../../type/Complex.js'), - collection = require('../../type/collection.js'), - - isNumber = util.number.isNumber, - isComplex = Complex.isComplex, - isCollection = collection.isCollection; - - /** - * Calculate the square root of a value - * - * sqrt(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ - math.sqrt = function sqrt (x) { - if (arguments.length != 1) { - throw new util.error.ArgumentsError('sqrt', arguments.length, 1); - } - - if (isNumber(x)) { - if (x >= 0) { - return Math.sqrt(x); - } - else { - return sqrt(new Complex(x, 0)); - } - } - - if (isComplex(x)) { - var r = Math.sqrt(x.re * x.re + x.im * x.im); - if (x.im >= 0) { - return Complex.create( - 0.5 * Math.sqrt(2.0 * (r + x.re)), - 0.5 * Math.sqrt(2.0 * (r - x.re)) - ); - } - else { - return Complex.create( - 0.5 * Math.sqrt(2.0 * (r + x.re)), - -0.5 * Math.sqrt(2.0 * (r - x.re)) - ); - } - } - - if (isCollection(x)) { - return collection.map(x, sqrt); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return sqrt(x.valueOf()); - } - - throw new util.error.UnsupportedTypeError('sqrt', x); - }; -}; diff --git a/src/function/arithmetic/square.js b/src/function/arithmetic/square.js deleted file mode 100644 index 7debfc6f4..000000000 --- a/src/function/arithmetic/square.js +++ /dev/null @@ -1,46 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Complex = require('../../type/Complex.js'), - collection = require('../../type/collection.js'), - - isNumber = util.number.isNumber, - isComplex = Complex.isComplex, - isCollection = collection.isCollection; - - /** - * Compute the square of a value - * - * x .* x - * square(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ - math.square = function square(x) { - if (arguments.length != 1) { - throw new util.error.ArgumentsError('square', arguments.length, 1); - } - - if (isNumber(x)) { - return x * x; - } - - if (isComplex(x)) { - return math.multiply(x, x); - } - - if (isCollection(x)) { - return collection.map(x, square); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return square(x.valueOf()); - } - - throw new util.error.UnsupportedTypeError('square', x); - }; -}; diff --git a/src/function/arithmetic/subtract.js b/src/function/arithmetic/subtract.js deleted file mode 100644 index 989e808b1..000000000 --- a/src/function/arithmetic/subtract.js +++ /dev/null @@ -1,94 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Complex = require('../../type/Complex.js'), - Matrix = require('../../type/Matrix.js'), - Unit = require('../../type/Unit.js'), - collection = require('../../type/collection.js'), - - isNumber = util.number.isNumber, - isString = util.string.isString, - isComplex = Complex.isComplex, - isUnit = Unit.isUnit, - isCollection = collection.isCollection; - - /** - * Subtract two values - * - * x - y - * subtract(x, y) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Unit | Array | Matrix} x - * @param {Number | Complex | Unit | Array | Matrix} y - * @return {Number | Complex | Unit | Array | Matrix} res - */ - math.subtract = function subtract(x, y) { - if (arguments.length != 2) { - throw new util.error.ArgumentsError('subtract', arguments.length, 2); - } - - if (isNumber(x)) { - if (isNumber(y)) { - // number - number - return x - y; - } - else if (isComplex(y)) { - // number - complex - return Complex.create ( - x - y.re, - - y.im - ); - } - } - else if (isComplex(x)) { - if (isNumber(y)) { - // complex - number - return Complex.create ( - x.re - y, - x.im - ) - } - else if (isComplex(y)) { - // complex - complex - return Complex.create ( - x.re - y.re, - x.im - y.im - ) - } - } - else if (isUnit(x)) { - if (isUnit(y)) { - if (!x.equalBase(y)) { - throw new Error('Units do not match'); - } - - if (x.value == null) { - throw new Error('Unit on left hand side of operator - has an undefined value'); - } - - if (y.value == null) { - throw new Error('Unit on right hand side of operator - has an undefined value'); - } - - var res = x.clone(); - res.value -= y.value; - res.fixPrefix = false; - - return res; - } - } - - if (isCollection(x) || isCollection(y)) { - return collection.map2(x, y, subtract); - } - - if (x.valueOf() !== x || y.valueOf() !== y) { - // fallback on the objects primitive values - return subtract(x.valueOf(), y.valueOf()); - } - - throw new util.error.UnsupportedTypeError('subtract', x, y); - }; -}; diff --git a/src/function/arithmetic/unary.js b/src/function/arithmetic/unary.js deleted file mode 100644 index 0375aebab..000000000 --- a/src/function/arithmetic/unary.js +++ /dev/null @@ -1,55 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Complex = require('../../type/Complex.js'), - Unit = require('../../type/Unit.js'), - collection = require('../../type/collection.js'), - - isNumber = util.number.isNumber, - isComplex = Complex.isComplex, - isUnit = Unit.isUnit, - isCollection = collection.isCollection; - - /** - * Inverse the sign of a value. - * - * -x - * unary(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Unit | Array | Matrix} x - * @return {Number | Complex | Unit | Array | Matrix} res - */ - math.unary = function unary(x) { - if (arguments.length != 1) { - throw new util.error.ArgumentsError('unary', arguments.length, 1); - } - - if (isNumber(x)) { - return -x; - } - else if (isComplex(x)) { - return Complex.create( - -x.re, - -x.im - ); - } - else if (isUnit(x)) { - var res = x.clone(); - res.value = -x.value; - return res; - } - - if (isCollection(x)) { - return collection.map(x, unary); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return unary(x.valueOf()); - } - - throw new util.error.UnsupportedTypeError('unary', x); - }; -}; diff --git a/src/function/arithmetic/unequal.js b/src/function/arithmetic/unequal.js deleted file mode 100644 index 39b828b4f..000000000 --- a/src/function/arithmetic/unequal.js +++ /dev/null @@ -1,66 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Complex = require('../../type/Complex.js'), - Unit = require('../../type/Unit.js'), - collection = require('../../type/collection.js'), - - isNumber = util.number.isNumber, - isString = util.string.isString, - isComplex = Complex.isComplex, - isUnit = Unit.isUnit, - isCollection = collection.isCollection; - - /** - * Check if value x unequals y, x != y - * In case of complex numbers, x.re must unequal y.re, or x.im must unequal y.im - * @param {Number | Complex | Unit | String | Array | Matrix | Range} x - * @param {Number | Complex | Unit | String | Array | Matrix | Range} y - * @return {Boolean | Array | Matrix} res - */ - math.unequal = function unequal(x, y) { - if (arguments.length != 2) { - throw new util.error.ArgumentsError('unequal', arguments.length, 2); - } - - if (isNumber(x)) { - if (isNumber(y)) { - return x != y; - } - else if (isComplex(y)) { - return (x != y.re) || (y.im != 0); - } - } - - if (isComplex(x)) { - if (isNumber(y)) { - return (x.re != y) || (x.im != 0); - } - else if (isComplex(y)) { - return (x.re != y.re) || (x.im != y.im); - } - } - - if ((isUnit(x)) && (isUnit(y))) { - if (!x.equalBase(y)) { - throw new Error('Cannot compare units with different base'); - } - return x.value != y.value; - } - - if (isString(x) || isString(y)) { - return x != y; - } - - if (isCollection(x) || isCollection(y)) { - return collection.map2(x, y, unequal); - } - - if (x.valueOf() !== x || y.valueOf() !== y) { - // fallback on the objects primitive values - return unequal(x.valueOf(), y.valueOf()); - } - - throw new util.error.UnsupportedTypeError('unequal', x, y); - }; -}; diff --git a/src/function/arithmetic/xgcd.js b/src/function/arithmetic/xgcd.js deleted file mode 100644 index 906b0b9a7..000000000 --- a/src/function/arithmetic/xgcd.js +++ /dev/null @@ -1,45 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - isNumber = util.number.isNumber, - isInteger = util.number.isInteger; - - /** - * Calculate the extended greatest common divisor for two values. - * - * xgcd(a, b) - * - * @param {Number} a An integer number - * @param {Number} b An integer number - * @return {Array} An array containing 3 integers [div, m, n] - * where div = gcd(a, b) and a*m + b*n = div - * - * @see http://en.wikipedia.org/wiki/Extended_Euclidean_algorithm - */ - math.xgcd = function xgcd(a, b) { - if (arguments.length == 2) { - // two arguments - if (isNumber(a) && isNumber(b)) { - if (!isInteger(a) || !isInteger(b)) { - throw new Error('Parameters in function xgcd must be integer numbers'); - } - - if(b == 0) { - return [a, 1, 0]; - } - - var tmp = xgcd(b, a % b), - div = tmp[0], - x = tmp[1], - y = tmp[2]; - - return [div, y, x - y * Math.floor(a / b)]; - } - - throw new util.error.UnsupportedTypeError('xgcd', a, b); - } - - // zero or one argument - throw new SyntaxError('Function xgcd expects two arguments'); - }; -}; diff --git a/src/function/complex/arg.js b/src/function/complex/arg.js deleted file mode 100644 index a7bd691ff..000000000 --- a/src/function/complex/arg.js +++ /dev/null @@ -1,47 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Complex = require('../../type/Complex.js'), - collection = require('../../type/collection.js'), - - isNumber = util.number.isNumber, - isCollection =collection.isCollection, - isComplex = Complex.isComplex; - - /** - * Compute the argument of a complex value. - * If x = a + bi, the argument is computed as atan2(b, a). - * - * arg(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Array | Matrix} res - */ - math.arg = function arg(x) { - if (arguments.length != 1) { - throw new util.error.ArgumentsError('arg', arguments.length, 1); - } - - if (isNumber(x)) { - return Math.atan2(0, x); - } - - if (isComplex(x)) { - return Math.atan2(x.im, x.re); - } - - if (isCollection(x)) { - return collection.map(x, arg); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return arg(x.valueOf()); - } - - // handle other types just as non-complex values - return math.atan2(0, x); - }; -}; diff --git a/src/function/complex/conj.js b/src/function/complex/conj.js deleted file mode 100644 index 5790e1444..000000000 --- a/src/function/complex/conj.js +++ /dev/null @@ -1,48 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Complex = require('../../type/Complex.js'), - collection = require('../../type/collection.js'), - - object = util.object, - isNumber = util.number.isNumber, - isCollection =collection.isCollection, - isComplex = Complex.isComplex; - - /** - * Compute the complex conjugate of a complex value. - * If x = a+bi, the complex conjugate is a-bi. - * - * conj(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ - math.conj = function conj(x) { - if (arguments.length != 1) { - throw new util.error.ArgumentsError('conj', arguments.length, 1); - } - - if (isNumber(x)) { - return x; - } - - if (isComplex(x)) { - return Complex.create(x.re, -x.im); - } - - if (isCollection(x)) { - return collection.map(x, conj); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return conj(x.valueOf()); - } - - // return a clone of the value for non-complex values - return object.clone(x); - }; -}; diff --git a/src/function/complex/im.js b/src/function/complex/im.js deleted file mode 100644 index 9ce9aa552..000000000 --- a/src/function/complex/im.js +++ /dev/null @@ -1,46 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Complex = require('../../type/Complex.js'), - collection = require('../../type/collection.js'), - - isNumber = util.number.isNumber, - isCollection =collection.isCollection, - isComplex = Complex.isComplex; - - /** - * Get the imaginary part of a complex number. - * - * im(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Array | Matrix} im - */ - math.im = function im(x) { - if (arguments.length != 1) { - throw new util.error.ArgumentsError('im', arguments.length, 1); - } - - if (isNumber(x)) { - return 0; - } - - if (isComplex(x)) { - return x.im; - } - - if (isCollection(x)) { - return collection.map(x, im); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return im(x.valueOf()); - } - - // return 0 for all non-complex values - return 0; - }; -}; diff --git a/src/function/complex/re.js b/src/function/complex/re.js deleted file mode 100644 index 1b26b49d4..000000000 --- a/src/function/complex/re.js +++ /dev/null @@ -1,47 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Complex = require('../../type/Complex.js'), - collection = require('../../type/collection.js'), - - object = util.object, - isNumber = util.number.isNumber, - isCollection =collection.isCollection, - isComplex = Complex.isComplex; - - /** - * Get the real part of a complex number. - * - * re(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Array | Matrix} re - */ - math.re = function re(x) { - if (arguments.length != 1) { - throw new util.error.ArgumentsError('re', arguments.length, 1); - } - - if (isNumber(x)) { - return x; - } - - if (isComplex(x)) { - return x.re; - } - - if (isCollection(x)) { - return collection.map(x, re); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return re(x.valueOf()); - } - - // return a clone of the value itself for all non-complex values - return object.clone(x); - }; -}; diff --git a/src/function/construction/boolean.js b/src/function/construction/boolean.js deleted file mode 100644 index 0493cb55f..000000000 --- a/src/function/construction/boolean.js +++ /dev/null @@ -1,48 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - isNumber = util.number.isNumber, - isString = util.string.isString; - - /** - * Create a boolean or convert a string or number to a boolean. - * In case of a number, true is returned for non-zero numbers, and false in - * case of zero. - * Strings can be 'true' or 'false', or can contain a number. - * @param {String | Number | Boolean} value - * @return {Boolean} bool - */ - math['boolean'] = function bool (value) { - if (arguments.length != 1) { - throw new util.error.ArgumentsError('boolean', arguments.length, 0, 1); - } - - if (value === 'true' || value === true) { - return true; - } - else if (value === 'false' || value === false) { - return false; - } - else if (isNumber(value)) { - return (value !== 0); - } - else if (isString(value)) { - // try case insensitive - var lcase = value.toLowerCase(); - if (lcase === 'true') { - return true; - } - else if (lcase === 'false') { - return false; - } - - // try whether a number - var num = Number(value); - if (value != '' && !isNaN(num)) { - return (num !== 0); - } - } - - throw new SyntaxError(value.toString() + ' is no valid boolean'); - }; -}; diff --git a/src/function/construction/complex.js b/src/function/construction/complex.js deleted file mode 100644 index fa8384411..000000000 --- a/src/function/construction/complex.js +++ /dev/null @@ -1,69 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Complex = require('../../type/Complex.js'), - - isString = util.string.isString, - isComplex = Complex.isComplex; - - /** - * Create a complex value. Depending on the passed arguments, the function - * will create and return a new math.type.Complex object. - * - * The method accepts the following arguments: - * complex() creates a complex value with zero - * as real and imaginary part. - * complex(re : number, im : string) creates a complex value with provided - * values for real and imaginary part. - * complex(arg : string) parses a string into a complex value. - * - * Example usage: - * var a = math.complex(3, -4); // 3 - 4i - * a.re = 5; // a = 5 - 4i - * var i = a.im; // -4; - * var b = math.complex('2 + 6i'); // 2 + 6i - * var c = math.complex(); // 0 + 0i - * var d = math.add(a, b); // 5 + 2i - * - * @param {*} [args] - * @return {Complex} value - */ - math.complex = function complex(args) { - switch (arguments.length) { - case 0: - // no parameters. Set re and im zero - return new Complex(0, 0); - break; - - case 1: - // parse string into a complex number - var arg = arguments[0]; - if (isComplex(arg)) { - // create a clone - return arg.clone(); - } - else if (isString(arg)) { - var c = Complex.parse(arg); - if (c) { - return c; - } - else { - throw new SyntaxError('String "' + arg + '" is no valid complex number'); - } - } - else { - throw new TypeError( - 'Two numbers or a single string expected in function complex'); - } - break; - - case 2: - // re and im provided - return new Complex(arguments[0], arguments[1]); - break; - - default: - throw new util.error.ArgumentsError('complex', arguments.length, 0, 2); - } - }; -}; diff --git a/src/function/construction/matrix.js b/src/function/construction/matrix.js deleted file mode 100644 index 5fd34b4ac..000000000 --- a/src/function/construction/matrix.js +++ /dev/null @@ -1,30 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Matrix = require('../../type/Matrix.js'); - - /** - * Create a matrix. The function creates a new math.type.Matrix object. - * - * The method accepts the following arguments: - * matrix() creates an empty matrix - * matrix(data) creates a matrix with initial data. - * - * Example usage: - * var m = matrix([[1, 2], [3, 4]); - * m.size(); // [2, 2] - * m.resize([3, 2], 5); - * m.valueOf(); // [[1, 2], [3, 4], [5, 5]] - * m.get([1, 0]) // 3 - * - * @param {Array | Matrix} [data] A multi dimensional array - * @return {Matrix} matrix - */ - math.matrix = function matrix(data) { - if (arguments.length > 1) { - throw new util.error.ArgumentsError('matrix', arguments.length, 0, 1); - } - - return new Matrix(data); - }; -}; diff --git a/src/function/construction/number.js b/src/function/construction/number.js deleted file mode 100644 index 81a6a3d08..000000000 --- a/src/function/construction/number.js +++ /dev/null @@ -1,26 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'); - - /** - * Create a number or convert a string to a number - * @param {String | Number | Boolean} [value] - * @return {Number} num - */ - math.number = function number (value) { - switch (arguments.length) { - case 0: - return 0; - case 1: - var num = Number(value); - if (isNaN(num)) { - num = Number(value.valueOf()); - } - if (isNaN(num)) { - throw new SyntaxError(value.toString() + ' is no valid number'); - } - return num; - default: - throw new util.error.ArgumentsError('number', arguments.length, 0, 1); - } - }; -}; diff --git a/src/function/construction/parser.js b/src/function/construction/parser.js deleted file mode 100644 index 3d3e7e56e..000000000 --- a/src/function/construction/parser.js +++ /dev/null @@ -1,45 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Parser = require('../../expr/Parser.js'); - - /** - * Create a parser. The function creates a new math.expr.Parser object. - * - * parser() - * - * Example usage: - * var parser = new math.parser(); - * - * // evaluate expressions - * var a = parser.eval('sqrt(3^2 + 4^2)'); // 5 - * var b = parser.eval('sqrt(-4)'); // 2i - * var c = parser.eval('2 inch in cm'); // 5.08 cm - * var d = parser.eval('cos(45 deg)'); // 0.7071067811865476 - * - * // define variables and functions - * parser.eval('x = 7 / 2'); // 3.5 - * parser.eval('x + 3'); // 6.5 - * parser.eval('function f(x, y) = x^y'); // f(x, y) - * parser.eval('f(2, 3)'); // 8 - * - * // get and set variables and functions - * var x = parser.get('x'); // 7 - * var f = parser.get('f'); // function - * var g = f(3, 2); // 9 - * parser.set('h', 500); - * var i = parser.eval('h / 2'); // 250 - * parser.set('hello', function (name) { - * return 'hello, ' + name + '!'; - * }); - * parser.eval('hello("user")'); // "hello, user!" - * - * // clear defined functions and variables - * parser.clear(); - * - * @return {Parser} Parser - */ - math.parser = function parser() { - return new Parser(math); - }; -}; diff --git a/src/function/construction/range.js b/src/function/construction/range.js deleted file mode 100644 index 8762d195b..000000000 --- a/src/function/construction/range.js +++ /dev/null @@ -1,73 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Range = require('../../type/Range.js'), - - isString = util.string.isString; - - /** - * Create a range. The function creates a new math.type.Range object. - * - * A range works similar to an Array, with functions like - * forEach and map. However, a Range object is very cheap to create compared to - * a large Array with indexes, as it stores only a start, step and end value of - * the range. - * - * The method accepts the following arguments - * range(str) Create a range from a string, where the - * string contains the start, optional step, - * and end, separated by a colon. - * range(start, end) Create a range with start and end and a - * default step size of 1 - * range(start, end, step) Create a range with start, step, and end. - * - * Example usage: - * var c = math.range(2, 6); // 2:1:5 - * c.toArray(); // [2, 3, 4, 5] - * var d = math.range(2, -3, -1); // 2:-1:-2 - * d.forEach(function (value, index) { - * console.log(index, value); - * }); - * var e = math.range('2:1:6'); // 2:1:6 - * - * @param {...*} args - * @return {Range} range - */ - math.range = function range(args) { - switch (arguments.length) { - case 1: - // parse string into a range - if (args instanceof Range) { - // create a clone - return args.clone(); - } - else if (isString(args)) { - var r = Range.parse(args); - if (r) { - return r; - } - else { - throw new SyntaxError('String "' + r + '" is no valid range'); - } - } - else { - throw new TypeError( - 'Two or three numbers or a single string expected in function range'); - } - break; - - case 2: - // range(start, end) - return new Range(arguments[0], arguments[1]); - break; - - case 3: - // range(start, end, step) - return new Range(arguments[0], arguments[1], arguments[2]); - break; - - default: - throw new util.error.ArgumentsError('range', arguments.length, 2, 3); - } - }; -}; diff --git a/src/function/construction/string.js b/src/function/construction/string.js deleted file mode 100644 index f27d37065..000000000 --- a/src/function/construction/string.js +++ /dev/null @@ -1,56 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - collection = require('../../type/collection.js'), - - number = util.number, - isNumber = util.number.isNumber, - isCollection = collection.isCollection; - - /** - * Create a string or convert any object into a string - * @param {*} [value] - * @return {String} str - */ - math.string = function string (value) { - switch (arguments.length) { - case 0: - return ''; - - case 1: - return _toString(value); - - default: - throw new util.error.ArgumentsError('string', arguments.length, 0, 1); - } - }; - - /** - * Recursive toString function - * @param {*} value Value can be anything: number, string, array, Matrix, ... - * @returns {String} str - * @private - */ - function _toString(value) { - if (isCollection(value)) { - var array = value.valueOf(); - - var str = '['; - var len = array.length; - for (var i = 0; i < len; i++) { - if (i != 0) { - str += ', '; - } - str += _toString(array[i]); - } - str += ']'; - return str; - } - else if (isNumber(value)) { - return number.format(value); - } - else { - return value.toString(); - } - } -}; diff --git a/src/function/construction/unit.js b/src/function/construction/unit.js deleted file mode 100644 index e5a311ba1..000000000 --- a/src/function/construction/unit.js +++ /dev/null @@ -1,59 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Unit = require('../../type/Unit.js'), - - isString = util.string.isString; - - /** - * Create a unit. Depending on the passed arguments, the function - * will create and return a new math.type.Unit object. - * - * The method accepts the following arguments: - * unit(unit : string) - * unit(value : number, unit : string - * - * Example usage: - * var a = math.unit(5, 'cm'); // 50 mm - * var b = math.unit('23 kg'); // 23 kg - * var c = math.in(a, math.unit('m'); // 0.05 m - * - * @param {*} args - * @return {Unit} value - */ - math.unit = function unit(args) { - switch(arguments.length) { - case 1: - // parse a string - var arg = arguments[0]; - if (arg instanceof Unit) { - // create a clone of the unit - return arg.clone(); - } - else if (isString(arg)) { - if (Unit.isPlainUnit(arg)) { - return new Unit(null, arg); // a pure unit - } - - var u = Unit.parse(arg); // a unit with value, like '5cm' - if (u) { - return u; - } - - throw new SyntaxError('String "' + arg + '" is no valid unit'); - } - else { - throw new TypeError('A string or a number and string expected in function unit'); - } - break; - - case 2: - // a number and a unit - return new Unit(arguments[0], arguments[1]); - break; - - default: - throw new util.error.ArgumentsError('unit', arguments.length, 1, 2); - } - }; -}; diff --git a/src/function/matrix/concat.js b/src/function/matrix/concat.js deleted file mode 100644 index 69a7340b6..000000000 --- a/src/function/matrix/concat.js +++ /dev/null @@ -1,115 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Matrix = require('../../type/Matrix.js'), - collection = require('../../type/collection.js'), - - object = util.object, - array = util.array, - isNumber = util.number.isNumber, - isInteger = util.number.isInteger, - isCollection = collection.isCollection; - - /** - * Concatenate two or more matrices - * Usage: - * math.concat(A, B, C, ...) - * math.concat(A, B, C, ..., dim) - * - * Where the optional dim is the zero-based number of the dimension to be - * concatenated. - * - * @param {... Array | Matrix} args - * @return {Array | Matrix} res - */ - math.concat = function concat (args) { - var i, - len = arguments.length, - dim = -1, // zero-based dimension - prevDim, - asMatrix = false, - matrices = []; // contains multi dimensional arrays - - for (i = 0; i < len; i++) { - var arg = arguments[i]; - - // test whether we need to return a Matrix (if not we return an Array) - if (arg instanceof Matrix) { - asMatrix = true; - } - - if ((i == len - 1) && isNumber(arg)) { - // last argument contains the dimension on which to concatenate - prevDim = dim; - dim = arg; - - if (!isInteger(dim) || dim < 0) { - throw new TypeError('Dimension number must be a positive integer ' + - '(dim = ' + dim + ')'); - } - - if (i > 0 && dim > prevDim) { - throw new RangeError('Dimension out of range ' + - '(' + dim + ' > ' + prevDim + ')'); - } - } - else if (isCollection(arg)) { - // this is a matrix or array - var matrix = object.clone(arg).valueOf(); - var size = array.size(arg.valueOf()); - matrices[i] = matrix; - prevDim = dim; - dim = size.length - 1; - - // verify whether each of the matrices has the same number of dimensions - if (i > 0 && dim != prevDim) { - throw new RangeError('Dimension mismatch ' + - '(' + prevDim + ' != ' + dim + ')'); - } - } - else { - throw new util.error.UnsupportedTypeError('concat', arg); - } - } - - if (matrices.length == 0) { - throw new SyntaxError('At least one matrix expected'); - } - - var res = matrices.shift(); - while (matrices.length) { - res = _concat(res, matrices.shift(), dim, 0); - } - - return asMatrix ? new Matrix(res) : res; - }; - - /** - * Recursively concatenate two matrices. - * The contents of the matrices is not cloned. - * @param {Array} a Multi dimensional array - * @param {Array} b Multi dimensional array - * @param {Number} concatDim The dimension on which to concatenate (zero-based) - * @param {Number} dim The current dim (zero-based) - * @return {Array} c The concatenated matrix - * @private - */ - function _concat(a, b, concatDim, dim) { - if (dim < concatDim) { - // recurse into next dimension - if (a.length != b.length) { - throw new Error('Dimensions mismatch (' + a.length + ' != ' + b.length + ')'); - } - - var c = []; - for (var i = 0; i < a.length; i++) { - c[i] = _concat(a[i], b[i], concatDim, dim + 1); - } - return c; - } - else { - // concatenate this dimension - return a.concat(b); - } - } -}; diff --git a/src/function/matrix/det.js b/src/function/matrix/det.js deleted file mode 100644 index 32566a4bc..000000000 --- a/src/function/matrix/det.js +++ /dev/null @@ -1,143 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Matrix = require('../../type/Matrix.js'), - - object = util.object, - array = util.array, - string = util.string; - - /** - * @constructor det - * Calculate the determinant of a matrix - * - * det(x) - * - * @param {Array | Matrix} x - * @return {Number} determinant - */ - math.det = function det (x) { - if (arguments.length != 1) { - throw new util.error.ArgumentsError('det', arguments.length, 1); - } - - var size = array.size(x.valueOf()); - switch (size.length) { - case 0: - // scalar - return object.clone(x); - break; - - case 1: - // vector - if (size[0] == 1) { - return object.clone(x.valueOf()[0]); - } - else { - throw new RangeError('Matrix must be square ' + - '(size: ' + string.format(size) + ')'); - } - break; - - case 2: - // two dimensional array - var rows = size[0]; - var cols = size[1]; - if (rows == cols) { - return _det(x.valueOf(), rows, cols); - } - else { - throw new RangeError('Matrix must be square ' + - '(size: ' + string.format(size) + ')'); - } - break; - - default: - // multi dimensional array - throw new RangeError('Matrix must be two dimensional ' + - '(size: ' + string.format(size) + ')'); - } - }; - - /** - * Calculate the determinant of a matrix - * @param {Array[]} matrix A square, two dimensional matrix - * @param {Number} rows Number of rows of the matrix (zero-based) - * @param {Number} cols Number of columns of the matrix (zero-based) - * @returns {Number} det - * @private - */ - function _det (matrix, rows, cols) { - if (rows == 1) { - // this is a 1 x 1 matrix - return matrix[0][0]; - } - else if (rows == 2) { - // this is a 2 x 2 matrix - // the determinant of [a11,a12;a21,a22] is det = a11*a22-a21*a12 - return math.subtract( - math.multiply(matrix[0][0], matrix[1][1]), - math.multiply(matrix[1][0], matrix[0][1]) - ); - } - else { - // this is an n x n matrix - var d = 1; - var lead = 0; - for (var r = 0; r < rows; r++) { - if (lead >= cols) { - break; - } - var i = r; - // Find the pivot element. - while (matrix[i][lead] == 0) { - i++; - if (i == rows) { - i = r; - lead++; - if (lead == cols) { - // We found the last pivot. - if (object.deepEqual(matrix, eye(rows).valueOf())) { - return math.round(d, 6); - } else { - return 0; - } - } - } - } - if (i != r) { - // Swap rows i and r, which negates the determinant. - for (var a = 0; a < cols; a++) { - var temp = matrix[i][a]; - matrix[i][a] = matrix[r][a]; - matrix[r][a] = temp; - } - d *= -1; - } - // Scale row r and the determinant simultaneously. - var div = matrix[r][lead]; - for (var a = 0; a < cols; a++) { - matrix[r][a] = matrix[r][a] / div; - } - d *= div; - // Back-substitute upwards. - for (var j = 0; j < rows; j++) { - if (j != r) { - // Taking linear combinations does not change the det. - var c = matrix[j][lead]; - for (var a = 0; a < cols; a++) { - matrix[j][a] = matrix[j][a] - matrix[r][a] * c; - } - } - } - lead++; // Now looking for a pivot further right. - } - // If reduction did not result in the identity, the matrix is singular. - if (object.deepEqual(matrix, math.eye(rows).valueOf())) { - return math.round(d, 6); - } else { - return 0; - } - } - } -}; diff --git a/src/function/matrix/diag.js b/src/function/matrix/diag.js deleted file mode 100644 index 867dd8104..000000000 --- a/src/function/matrix/diag.js +++ /dev/null @@ -1,87 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Range = require('../../type/Range.js'), - Matrix = require('../../type/Matrix.js'), - - object = util.object, - isNumber = util.number.isNumber, - isInteger = util.number.isInteger; - - /** - * Create a diagonal matrix or retrieve the diagonal of a matrix - * - * diag(v) - * diag(v, k) - * diag(X) - * diag(X, k) - * - * TODO: more documentation on diag - * - * @param {Number | Matrix | Array} x - * @param {Number} [k] - * @return {Matrix} matrix - */ - math.diag = function diag (x, k) { - var data, vector, i, iMax; - - if (arguments.length != 1 && arguments.length != 2) { - throw new util.error.ArgumentsError('diag', arguments.length, 1, 2); - } - - if (k) { - if (!isNumber(k) || !isInteger(k)) { - throw new TypeError ('Second parameter in function diag must be an integer'); - } - } - else { - k = 0; - } - var kSuper = k > 0 ? k : 0; - var kSub = k < 0 ? -k : 0; - - // convert to matrix - if (!(x instanceof Matrix) && !(x instanceof Range)) { - x = new Matrix(x); - } - - // get as array when the matrix is a vector - var s; - if (x.isVector()) { - x = x.toVector(); - s = [x.length]; - } - else { - s = x.size(); - } - - switch (s.length) { - case 1: - // x is a vector. create diagonal matrix - vector = x.valueOf(); - var matrix = new Matrix(); - matrix.resize([vector.length + kSub, vector.length + kSuper]); - data = matrix.valueOf(); - iMax = vector.length; - for (i = 0; i < iMax; i++) { - data[i + kSub][i + kSuper] = object.clone(vector[i]); - } - return matrix; - break; - - case 2: - // x is a matrix get diagonal from matrix - vector = []; - data = x.valueOf(); - iMax = Math.min(s[0] - kSub, s[1] - kSuper); - for (i = 0; i < iMax; i++) { - vector[i] = object.clone(data[i + kSub][i + kSuper]); - } - return new Matrix(vector); - break; - - default: - throw new RangeError('Matrix for function diag must be 2 dimensional'); - } - }; -}; diff --git a/src/function/matrix/eye.js b/src/function/matrix/eye.js deleted file mode 100644 index d19367165..000000000 --- a/src/function/matrix/eye.js +++ /dev/null @@ -1,58 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Matrix = require('../../type/Matrix.js'), - collection = require('../../type/collection.js'), - - isNumber = util.number.isNumber, - isInteger = util.number.isInteger; - - /** - * Create an identity matrix with size m x n - * - * eye(m) - * eye(m, n) - * - * TODO: more documentation on eye - * - * @param {...Number | Matrix | Array} size - * @return {Matrix} matrix - */ - math.eye = function eye (size) { - var args = collection.argsToArray(arguments); - if (args.length == 0) { - args = [1, 1]; - } - else if (args.length == 1) { - args[1] = args[0]; - } - else if (args.length > 2) { - throw new util.error.ArgumentsError('eye', args.length, 0, 2); - } - - var rows = args[0], - cols = args[1]; - - if (!isNumber(rows) || !isInteger(rows) || rows < 1) { - throw new Error('Parameters in function eye must be positive integers'); - } - if (cols) { - if (!isNumber(cols) || !isInteger(cols) || cols < 1) { - throw new Error('Parameters in function eye must be positive integers'); - } - } - - // create and args the matrix - var matrix = new Matrix(); - matrix.resize(args); - - // fill in ones on the diagonal - var minimum = math.min(args); - var data = matrix.valueOf(); - for (var d = 0; d < minimum; d++) { - data[d][d] = 1; - } - - return matrix; - }; -}; diff --git a/src/function/matrix/inv.js b/src/function/matrix/inv.js deleted file mode 100644 index 6aa7fd286..000000000 --- a/src/function/matrix/inv.js +++ /dev/null @@ -1,185 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Matrix = require('../../type/Matrix.js'), - - string = util.string; - - /** - * Calculate the inverse of a matrix - * - * inv(x) - * - * TODO: more documentation on inv - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} inv - */ - math.inv = function inv (x) { - if (arguments.length != 1) { - throw new util.error.ArgumentsError('inv', arguments.length, 1); - } - var size = math.size(x).valueOf(); - switch (size.length) { - case 0: - // scalar - return math.divide(1, x); - break; - - case 1: - // vector - if (size[0] == 1) { - if (x instanceof Matrix) { - return new Matrix([ - math.divide(1, x.valueOf()[0]) - ]); - } - else { - return [ - math.divide(1, x[0]) - ]; - } - } - else { - throw new RangeError('Matrix must be square ' + - '(size: ' + string.format(size) + ')'); - } - break; - - case 2: - // two dimensional array - var rows = size[0]; - var cols = size[1]; - if (rows == cols) { - if (x instanceof Matrix) { - return new Matrix( - _inv(x.valueOf(), rows, cols) - ); - } - else { - // return an Array - return _inv(x, rows, cols); - } - } - else { - throw new RangeError('Matrix must be square ' + - '(size: ' + string.format(size) + ')'); - } - break; - - default: - // multi dimensional array - throw new RangeError('Matrix must be two dimensional ' + - '(size: ' + string.format(size) + ')'); - } - }; - - /** - * Calculate the inverse of a square matrix - * @param {Array[]} matrix A square matrix - * @param {Number} rows Number of rows - * @param {Number} cols Number of columns, must equal rows - * @return {Array[]} inv Inverse matrix - * @private - */ - function _inv (matrix, rows, cols){ - var r, s, f, value, temp; - - if (rows == 1) { - // this is a 1 x 1 matrix - value = matrix[0][0]; - if (value == 0) { - throw Error('Cannot calculate inverse, determinant is zero'); - } - return [[ - math.divide(1, value) - ]]; - } - else if (rows == 2) { - // this is a 2 x 2 matrix - var d = math.det(matrix); - if (d == 0) { - throw Error('Cannot calculate inverse, determinant is zero'); - } - return [ - [ - math.divide(matrix[1][1], d), - math.divide(math.unary(matrix[0][1]), d) - ], - [ - math.divide(math.unary(matrix[1][0]), d), - math.divide(matrix[0][0], d) - ] - ]; - } - else { - // this is a matrix of 3 x 3 or larger - // calculate inverse using gauss-jordan elimination - // http://en.wikipedia.org/wiki/Gaussian_elimination - // http://mathworld.wolfram.com/MatrixInverse.html - // http://math.uww.edu/~mcfarlat/inverse.htm - - // make a copy of the matrix (only the arrays, not of the elements) - var A = matrix.concat(); - for (r = 0; r < rows; r++) { - A[r] = A[r].concat(); - } - - // create an identity matrix which in the end will contain the - // matrix inverse - var B = math.eye(rows).valueOf(); - - // loop over all columns, and perform row reductions - for (var c = 0; c < cols; c++) { - // element Acc should be non zero. if not, swap content - // with one of the lower rows - r = c; - while (r < rows && A[r][c] == 0) { - r++; - } - if (r == rows || A[r][c] == 0) { - throw Error('Cannot calculate inverse, determinant is zero'); - } - if (r != c) { - temp = A[c]; A[c] = A[r]; A[r] = temp; - temp = B[c]; B[c] = B[r]; B[r] = temp; - } - - // eliminate non-zero values on the other rows at column c - var Ac = A[c], - Bc = B[c]; - for (r = 0; r < rows; r++) { - var Ar = A[r], - Br = B[r]; - if(r != c) { - // eliminate value at column c and row r - if (Ar[c] != 0) { - f = math.divide(math.unary(Ar[c]), Ac[c]); - - // add (f * row c) to row r to eliminate the value - // at column c - for (s = c; s < cols; s++) { - Ar[s] = math.add(Ar[s], math.multiply(f, Ac[s])); - } - for (s = 0; s < cols; s++) { - Br[s] = math.add(Br[s], math.multiply(f, Bc[s])); - } - } - } - else { - // normalize value at Acc to 1, - // divide each value on row r with the value at Acc - f = Ac[c]; - for (s = c; s < cols; s++) { - Ar[s] = math.divide(Ar[s], f); - } - for (s = 0; s < cols; s++) { - Br[s] = math.divide(Br[s], f); - } - } - } - } - return B; - } - } -}; diff --git a/src/function/matrix/ones.js b/src/function/matrix/ones.js deleted file mode 100644 index 5161f2660..000000000 --- a/src/function/matrix/ones.js +++ /dev/null @@ -1,36 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Matrix = require('../../type/Matrix.js'), - collection = require('../../type/collection.js'), - - array = util.array; - - /** - * Create a matrix filled with ones - * - * ones(n) - * ones(m, n) - * ones([m, n]) - * ones([m, n, p, ...]) - * - * @param {...Number | Array} size - * @return {Array | Matrix | Number} matrix - */ - math.ones = function ones (size) { - var args = collection.argsToArray(arguments); - var asMatrix = (size instanceof Matrix); - - if (args.length == 0) { - // output a scalar - return 1; - } - else { - // output an array or matrix - var res = []; - var defaultValue = 1; - array.resize(res, args, defaultValue); - return asMatrix ? new Matrix(res) : res; - } - }; -}; diff --git a/src/function/matrix/size.js b/src/function/matrix/size.js deleted file mode 100644 index 317407f2a..000000000 --- a/src/function/matrix/size.js +++ /dev/null @@ -1,50 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Complex = require('../../type/Complex.js'), - Unit = require('../../type/Unit.js'), - Matrix = require('../../type/Matrix.js'), - - array = util.array, - isNumber = util.number.isNumber, - isString = util.string.isString, - isComplex = Complex.isComplex, - isUnit = Unit.isUnit; - - /** - * Calculate the size of a matrix or scalar - * - * size(x) - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ - math.size = function size (x) { - if (arguments.length != 1) { - throw new util.error.ArgumentsError('size', arguments.length, 1); - } - - if (isNumber(x) || isComplex(x) || isUnit(x) || x == null) { - return []; - } - - if (isString(x)) { - return [x.length]; - } - - if (Array.isArray(x)) { - return array.size(x); - } - - if (x instanceof Matrix) { - return new Matrix(x.size()); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return size(x.valueOf()); - } - - throw new util.error.UnsupportedTypeError('size', x); - }; -}; diff --git a/src/function/matrix/squeeze.js b/src/function/matrix/squeeze.js deleted file mode 100644 index a42c25cfe..000000000 --- a/src/function/matrix/squeeze.js +++ /dev/null @@ -1,59 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Matrix = require('../../type/Matrix.js'), - - object = util.object, - isArray = Array.isArray; - - /** - * Remove singleton dimensions from a matrix - * - * squeeze(x) - * - * @param {Matrix | Array} x - * @return {Matrix | Array} res - */ - math.squeeze = function squeeze (x) { - if (arguments.length != 1) { - throw new util.error.ArgumentsError('squeeze', arguments.length, 1); - } - - if (isArray(x)) { - return _squeezeArray(object.clone(x)); - } - else if (x instanceof Matrix) { - return new Matrix(_squeezeArray(x.toArray())); - } - else if (isArray(x.valueOf())) { - return _squeezeArray(object.clone(x.valueOf())); - } - else { - // scalar - return object.clone(x); - } - }; - - /** - * Recursively squeeze a multi dimensional array - * @param {Array} array - * @return {Array} array - * @private - */ - function _squeezeArray(array) { - if (array.length == 1) { - // squeeze this array - return _squeezeArray(array[0]); - } - else { - // process all childs - for (var i = 0, len = array.length; i < len; i++) { - var child = array[i]; - if (isArray(child)) { - array[i] = _squeezeArray(child); - } - } - return array; - } - } -}; diff --git a/src/function/matrix/subset.js b/src/function/matrix/subset.js deleted file mode 100644 index 059390570..000000000 --- a/src/function/matrix/subset.js +++ /dev/null @@ -1,205 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Matrix = require('../../type/Matrix.js'), - Range = require('../../type/Range.js'), - - array = util.array, - isString = util.string.isString, - isArray = Array.isArray; - - /** - * Get or set a subset of a matrix or string - * - * Usage: - * var subset = math.subset(value, index) // retrieve subset - * var value = math.subset(value, index, replacement) // replace subset - * - * Where: - * {*} value An array, matrix, or scalar value - * {Array} index An array containing index values - * {*} replacement An array, matrix, or scalar - * - * @param args - * @return res - */ - math.subset = function subset (args) { - switch (arguments.length) { - case 2: // get subset - return _getSubset(arguments[0], arguments[1]); - - case 3: // set subset - return _setSubset(arguments[0], arguments[1], arguments[2]); - - default: // wrong number of arguments - throw new util.error.ArgumentsError('subset', arguments.length, 2, 3); - } - }; - - /** - * Retrieve a subset of an value such as an Array, Matrix, or String - * @param {*} value Object from which to get a subset - * @param {Array[] | Range[] | Number[] | Matrix} index - * Two dimensional array (size 1 x n) containing - * the indexes to be retrieved. Can also be a two - * dimensional Matrix (size 1 x n), or an Array - * (size 1) containing a Range or a Number. - * @returns {*} subset - * @private - */ - function _getSubset(value, index) { - var m, subset; - - if (isArray(value) || value instanceof Range) { - m = new Matrix(value); - subset = m.get(index); - return subset.valueOf(); - } - else if (value instanceof Matrix) { - return value.get(index); - } - else if (isString(value)) { - return _getSubstring(value, index); - } - else { - // scalar - m = new Matrix([value]); - subset = m.get(index); - return subset.valueOf(); - } - } - - /** - * Retrieve a subset of a string - * @param {String} str String from which to get a substring - * @param {Array[] | Range[] | Number[] | Matrix} index - * Two dimensional array (size 1 x n) containing - * the indexes to be retrieved. Can also be a two - * dimensional Matrix (size 1 x n), or an Array - * (size 1) containing a Range or a Number. - * @returns {string} substring - * @private - */ - function _getSubstring(str, index) { - var i, len; - index = index.valueOf(); // cast from matrix or range to array - if (index.length != 1) { - throw new RangeError('Dimension mismatch (' + index.length + ' != 1)'); - } - - if (isArray(index)) { - index = index[0]; // read first dimension - } - index = index.valueOf(); // cast from matrix or range to array - if (!isArray(index)) { - index = [index]; - } - - var substr = ''; - var strLen = str.length; - for (i = 0, len = index.length; i < len; i++) { - var index_i = index[i]; - array.validateIndex(index_i, strLen); - substr += str.charAt(index_i); // index_i is zero based - } - - return substr; - } - - /** - * Replace a subset in an value such as an Array, Matrix, or String - * @param {*} value Object to be replaced - * @param {Array[] | Range[] | Number[] | Matrix} index - * Two dimensional array (size 1 x n) containing - * the indexes to be replaced. Can also be a two - * dimensional Matrix (size 1 x n), or an Array - * (size 1) containing a Range. - * @param {String} replacement - * @returns {*} result - * @private - */ - function _setSubset(value, index, replacement) { - if (isArray(value) || value instanceof Range) { - var m = new Matrix(math.clone(value)); - m.set(index, replacement); - return m.valueOf(); - } - else if (value instanceof Matrix) { - return value.clone().set(index, replacement); - } - else if (isString(value)) { - return _setSubstring(value, index, replacement); - } - else { - // scalar - m = new Matrix([value]); - m.set(index, replacement); - - if (m.isScalar()) { - // still a scalar - return m.toScalar(); - } - else { - // changed into a matrix. return array - return m.valueOf(); - } - } - } - - /** - * Replace a substring in a string - * @param {String} str String to be replaced - * @param {Array[] | Range[] | Number[] | Matrix} index - * Two dimensional array (size 1 x n) containing - * the indexes to be replaced. Can also be a two - * dimensional Matrix (size 1 x n), or an Array - * (size 1) containing a Range. - * @param {String} replacement Replacement string - * @returns {string} result - * @private - */ - function _setSubstring(str, index, replacement) { - var i, len; - index = index.valueOf(); // cast from matrix or range to array - - if (index.length != 1) { - throw new RangeError('Dimension mismatch (' + index.length + ' != 1)'); - } - if (isArray(index)) { - index = index[0]; // read first dimension - } - index = index.valueOf(); // cast from matrix or range to array - if (!isArray(index)) { - index = [index]; - } - - if (index.length != replacement.length) { - throw new RangeError('Dimension mismatch ' + - '(' + index.length + ' != ' + replacement.length + ')'); - } - - // copy the string into an array with characters - var strLen = str.length; - var chars = []; - for (i = 0; i < strLen; i++) { - chars[i] = str.charAt(i); - } - - for (i = 0, len = index.length; i < len; i++) { - var index_i = index[i]; - array.validateIndex(index_i); - chars[index_i] = replacement.charAt(i); // index_i is zero based - } - - // initialize undefined characters with a space - if (chars.length > strLen) { - for (i = strLen - 1, len = chars.length; i < len; i++) { - if (!chars[i]) { - chars[i] = ' '; - } - } - } - - return chars.join(''); - } -}; diff --git a/src/function/matrix/transpose.js b/src/function/matrix/transpose.js deleted file mode 100644 index acde1a1cf..000000000 --- a/src/function/matrix/transpose.js +++ /dev/null @@ -1,68 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Matrix = require('../../type/Matrix.js'), - - object = util.object, - string = util.string; - - /** - * Create the transpose of a matrix - * - * transpose(x) - * - * @param {Array | Matrix} x - * @return {Array | Matrix} transpose - */ - math.transpose = function transpose (x) { - if (arguments.length != 1) { - throw new util.error.ArgumentsError('transpose', arguments.length, 1); - } - - var size = math.size(x).valueOf(); - switch (size.length) { - case 0: - // scalar - return object.clone(x); - break; - - case 1: - // vector - return object.clone(x); - break; - - case 2: - // two dimensional array - var rows = size[1], - cols = size[0], - asMatrix = Matrix.isMatrix(x), - data = x.valueOf(), - transposed = [], - transposedRow, - clone = object.clone; - - if (rows === 0) { - // whoops - throw new RangeError('Cannot transpose a 2D matrix with no rows' + - '(size: ' + string.format(size) + ')'); - } - - for (var r = 0; r < rows; r++) { - transposedRow = transposed[r] = []; - for (var c = 0; c < cols; c++) { - transposedRow[c] = clone(data[c][r]); - } - } - if (cols == 0) { - transposed[0] = []; - } - return asMatrix ? new Matrix(transposed) : transposed; - break; - - default: - // multi dimensional array - throw new RangeError('Matrix must be two dimensional ' + - '(size: ' + string.format(size) + ')'); - } - }; -}; diff --git a/src/function/matrix/zeros.js b/src/function/matrix/zeros.js deleted file mode 100644 index 522cb4aa9..000000000 --- a/src/function/matrix/zeros.js +++ /dev/null @@ -1,36 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Matrix = require('../../type/Matrix.js'), - collection = require('../../type/collection.js'), - - array = util.array; - - /** - * create a matrix filled with zeros - * - * zeros(n) - * zeros(m, n) - * zeros([m, n]) - * zeros([m, n, p, ...]) - * - * @param {...Number | Array} size - * @return {Array | Matrix | Number} matrix - */ - math.zeros = function zeros (size) { - var args = collection.argsToArray(arguments); - var asMatrix = (size instanceof Matrix); - - if (args.length == 0) { - // output a scalar - return 0; - } - else { - // output an array or matrix - var res = []; - var defaultValue = 0; - array.resize(res, args, defaultValue); - return asMatrix ? new Matrix(res) : res; - } - }; -}; diff --git a/src/function/probability/factorial.js b/src/function/probability/factorial.js deleted file mode 100644 index a5e26ebb0..000000000 --- a/src/function/probability/factorial.js +++ /dev/null @@ -1,58 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - collection = require('../../type/collection.js'), - - isNumber = util.number.isNumber, - isInteger = util.number.isInteger, - isCollection = collection.isCollection; - - /** - * Compute the factorial of a value - * - * x! - * factorial(x) - * - * Factorial only supports an integer value as argument. - * For matrices, the function is evaluated element wise. - * - * @Param {Number | Array | Matrix} x - * @return {Number | Array | Matrix} res - */ - math.factorial = function factorial (x) { - if (arguments.length != 1) { - throw new util.error.ArgumentsError('factorial', arguments.length, 1); - } - - if (isNumber(x)) { - if (!isInteger(x) || x < 0) { - throw new TypeError('Positive integer value expected in function factorial'); - } - - var value = x, - res = value; - value--; - while (value > 1) { - res *= value; - value--; - } - - if (res == 0) { - res = 1; // 0! is per definition 1 - } - - return res; - } - - if (isCollection(x)) { - return collection.map(x, factorial); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return factorial(x.valueOf()); - } - - throw new util.error.UnsupportedTypeError('factorial', x); - }; -}; diff --git a/src/function/probability/random.js b/src/function/probability/random.js deleted file mode 100644 index 12b214c22..000000000 --- a/src/function/probability/random.js +++ /dev/null @@ -1,166 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Matrix = require('../../type/Matrix.js'); - - /** - * Return a random number between 0 and 1 - * - * random() - * - * @return {Number} res - */ - - // Each distribution is a function that takes no argument and when called returns - // a number between 0 and 1. - var distributions = { - - uniform: function() { - return Math.random; - }, - - // Implementation of normal distribution using Box-Muller transform - // ref : http://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform - // We take : mean = 0.5, standard deviation = 1/6 - // so that 99.7% values are in [0, 1]. - normal: function() { - return function() { - var u1, u2, - picked = -1; - // We reject values outside of the interval [0, 1] - // TODO: check if it is ok to do that? - while (picked < 0 || picked > 1) { - u1 = Math.random(); - u2 = Math.random(); - picked = 1/6 * Math.pow(-2 * Math.log(u1), 0.5) * Math.cos(2 * Math.PI * u2) + 0.5; - } - return picked; - } - } - }; - - /** - * Create a distribution object. - * @param {String} name Name of a distribution. - * Choose from 'uniform', 'normal'. - * @return {Object} distribution A distribution object containing functions: - * random([size, min, max]) - * randomInt([min, max]) - * pickRandom(array) - */ - math.distribution = function(name) { - if (!distributions.hasOwnProperty(name)) - throw new Error('unknown distribution ' + name); - - var args = Array.prototype.slice.call(arguments, 1), - distribution = distributions[name].apply(this, args); - - return (function(distribution) { - - // This is the public API for all distributions - var randFunctions = { - - random: function(arg1, arg2, arg3) { - var size, min, max; - if (arguments.length > 3) { - throw new util.error.ArgumentsError('random', arguments.length, 0, 3); - - // `random(max)` or `random(size)` - } else if (arguments.length === 1) { - if (Object.prototype.toString.call(arg1) === '[object Array]') - size = arg1; - else - max = arg1; - // `random(min, max)` or `random(size, max)` - } else if (arguments.length === 2) { - if (Object.prototype.toString.call(arg1) === '[object Array]') - size = arg1; - else { - min = arg1; - max = arg2; - } - // `random(size, min, max)` - } else { - size = arg1; - min = arg2; - max = arg3; - } - - if (max === undefined) max = 1; - if (min === undefined) min = 0; - if (size !== undefined) return new Matrix(_randomDataForMatrix(size, min, max, _random)); - else return _random(min, max); - }, - - randomInt: function(arg1, arg2, arg3) { - var size, min, max; - if (arguments.length > 3 || arguments.length < 1) - throw new util.error.ArgumentsError('randomInt', arguments.length, 1, 3); - - // `randomInt(max)` - else if (arguments.length === 1) max = arg1; - // `randomInt(min, max)` or `randomInt(size, max)` - else if (arguments.length === 2) { - if (Object.prototype.toString.call(arg1) === '[object Array]') - size = arg1; - else { - min = arg1; - max = arg2; - } - // `randomInt(size, min, max)` - } else { - size = arg1; - min = arg2; - max = arg3; - } - - if (min === undefined) min = 0; - if (size !== undefined) return new Matrix(_randomDataForMatrix(size, min, max, _randomInt)); - else return _randomInt(min, max); - }, - - pickRandom: function(possibles) { - if (arguments.length !== 1) - throw new util.error.ArgumentsError('pickRandom', arguments.length, 1); - return possibles[Math.floor(Math.random() * possibles.length)]; - } - - }; - - var _random = function(min, max) { - return min + distribution() * (max - min); - }; - - var _randomInt = function(min, max) { - return Math.floor(min + distribution() * (max - min)); - }; - - // This is a function for generating a random matrix recursively. - var _randomDataForMatrix = function(size, min, max, randFunc) { - var data = [], length, i; - size = size.slice(0); - - if (size.length > 1) { - for (i = 0, length = size.shift(); i < length; i++) - data.push(_randomDataForMatrix(size, min, max, randFunc)); - } else { - for (i = 0, length = size.shift(); i < length; i++) - data.push(randFunc(min, max)); - } - - return data; - }; - - return randFunctions; - - })(distribution); - - }; - - // Default random functions use uniform distribution - // TODO: put random functions in separate files? - var uniformRandFunctions = math.distribution('uniform'); - math.random = uniformRandFunctions.random; - math.randomInt = uniformRandFunctions.randomInt; - math.pickRandom = uniformRandFunctions.pickRandom; -}; diff --git a/src/function/statistics/max.js b/src/function/statistics/max.js deleted file mode 100644 index cd4614aca..000000000 --- a/src/function/statistics/max.js +++ /dev/null @@ -1,103 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Matrix = require('../../type/Matrix.js'), - collection = require('../../type/collection.js'), - - isCollection = collection.isCollection; - - /** - * Compute the maximum value of a list of values - * - * max(a, b, c, ...) - * max([a, b, c, ...]) - * - * @param {... *} args A single matrix or or multiple scalar values - * @return {*} res - */ - math.max = function max(args) { - if (arguments.length == 0) { - throw new Error('Function max requires one or more parameters (0 provided)'); - } - - if (isCollection(args)) { - // max([a, b, c, d, ...]]) - if (arguments.length > 1) { - throw Error('Wrong number of parameters (1 matrix or multiple scalars expected)'); - } - - var size = math.size(args).valueOf(); - - if (size.length == 1) { - // vector - if (args.length == 0) { - throw new Error('Cannot calculate max of an empty vector'); - } - - return _max(args.valueOf()); - } - else if (size.length == 2) { - // 2 dimensional matrix - if (size[0] == 0 || size[1] == 0) { - throw new Error('Cannot calculate max of an empty matrix'); - } - - // TODO: make a generic collection method for this - if (Matrix.isMatrix(args)) { - return new Matrix(_max2(args.valueOf(), size[0], size[1])); - } - else { - return _max2(args, size[0], size[1]); - } - } - else { - // TODO: implement max for n-dimensional matrices - throw new RangeError('Cannot calculate max for multi dimensional matrix'); - } - } - else { - // max(a, b, c, d, ...) - return _max(arguments); - } - }; - - /** - * Calculate the max of a one dimensional array - * @param {Array} array - * @return {Number} max - * @private - */ - function _max(array) { - var res = array[0]; - for (var i = 1, iMax = array.length; i < iMax; i++) { - var value = array[i]; - if (math.larger(value, res)) { - res = value; - } - } - return res; - } - - /** - * Calculate the max of a two dimensional array - * @param {Array} array - * @param {Number} rows - * @param {Number} cols - * @return {Number[]} max - * @private - */ - function _max2(array, rows, cols) { - var res = []; - for (var c = 0; c < cols; c++) { - var max = array[0][c]; - for (var r = 1; r < rows; r++) { - var value = array[r][c]; - if (math.larger(value, max)) { - max = value; - } - } - res[c] = max; - } - return res; - } -}; diff --git a/src/function/statistics/min.js b/src/function/statistics/min.js deleted file mode 100644 index a1260a079..000000000 --- a/src/function/statistics/min.js +++ /dev/null @@ -1,103 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Matrix = require('../../type/Matrix.js'), - collection = require('../../type/collection.js'), - - isCollection = collection.isCollection; - - /** - * Compute the minimum value of a list of values - * - * min(a, b, c, ...) - * min([a, b, c, ...]) - * - * @param {... *} args A single matrix or multiple scalars - * @return {*} res - */ - math.min = function min(args) { - if (arguments.length == 0) { - throw new Error('Function min requires one or more parameters (0 provided)'); - } - - if (isCollection(args)) { - // min([a, b, c, d, ...]]) - if (arguments.length > 1) { - throw Error('Wrong number of parameters (1 matrix or multiple scalars expected)'); - } - - var size = math.size(args).valueOf(); - - if (size.length == 1) { - // vector - if (args.length == 0) { - throw new Error('Cannot calculate min of an empty vector'); - } - - return _min(args.valueOf()); - } - else if (size.length == 2) { - // 2 dimensional matrix - if (size[0] == 0 || size[1] == 0) { - throw new Error('Cannot calculate min of an empty matrix'); - } - - // TODO: make a generic collection method for this - if (Matrix.isMatrix(args)) { - return new Matrix(_min2(args.valueOf(), size[0], size[1])); - } - else { - return _min2(args, size[0], size[1]); - } - } - else { - // TODO: implement min for n-dimensional matrices - throw new RangeError('Cannot calculate min for multi dimensional matrix'); - } - } - else { - // min(a, b, c, d, ...) - return _min(arguments); - } - }; - - /** - * Calculate the min of a one dimensional array - * @param {Array} array - * @return {Number} min - * @private - */ - function _min(array) { - var res = array[0]; - for (var i = 1, iMax = array.length; i < iMax; i++) { - var value = array[i]; - if (math.smaller(value, res)) { - res = value; - } - } - return res; - } - - /** - * Calculate the min of a two dimensional array - * @param {Array} array - * @param {Number} rows - * @param {Number} cols - * @return {Number[]} min - * @private - */ - function _min2(array, rows, cols) { - var res = []; - for (var c = 0; c < cols; c++) { - var min = array[0][c]; - for (var r = 1; r < rows; r++) { - var value = array[r][c]; - if (math.smaller(value, min)) { - min = value; - } - } - res[c] = min; - } - return res; - } -}; diff --git a/src/function/trigonometry/acos.js b/src/function/trigonometry/acos.js deleted file mode 100644 index 04dfc7757..000000000 --- a/src/function/trigonometry/acos.js +++ /dev/null @@ -1,85 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Complex = require('../../type/Complex.js'), - collection = require('../../type/collection.js'), - - isNumber = util.number.isNumber, - isComplex = Complex.isComplex, - isCollection = collection.isCollection; - - /** - * Calculate the inverse cosine of a value - * - * acos(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - * - * @see http://mathworld.wolfram.com/InverseCosine.html - */ - math.acos = function acos(x) { - if (arguments.length != 1) { - throw new util.error.ArgumentsError('acos', arguments.length, 1); - } - - if (isNumber(x)) { - if (x >= -1 && x <= 1) { - return Math.acos(x); - } - else { - return acos(new Complex(x, 0)); - } - } - - if (isComplex(x)) { - // acos(z) = 0.5*pi + i*log(iz + sqrt(1-z^2)) - var temp1 = Complex.create( - x.im * x.im - x.re * x.re + 1.0, - -2.0 * x.re * x.im - ); - var temp2 = math.sqrt(temp1); - var temp3; - if (temp2 instanceof Complex) { - temp3 = Complex.create( - temp2.re - x.im, - temp2.im + x.re - ) - } - else { - temp3 = Complex.create( - temp2 - x.im, - x.re - ) - } - var temp4 = math.log(temp3); - - // 0.5*pi = 1.5707963267948966192313216916398 - if (temp4 instanceof Complex) { - return Complex.create( - 1.57079632679489661923 - temp4.im, - temp4.re - ); - } - else { - return new Complex( - 1.57079632679489661923, - temp4 - ); - } - } - - if (isCollection(x)) { - return collection.map(x, acos); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return acos(x.valueOf()); - } - - throw new util.error.UnsupportedTypeError('acos', x); - }; -}; diff --git a/src/function/trigonometry/asin.js b/src/function/trigonometry/asin.js deleted file mode 100644 index 97a24ac17..000000000 --- a/src/function/trigonometry/asin.js +++ /dev/null @@ -1,82 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Complex = require('../../type/Complex.js'), - collection = require('../../type/collection.js'), - - isNumber = util.number.isNumber, - isComplex = Complex.isComplex, - isCollection = collection.isCollection; - - /** - * Calculate the inverse sine of a value - * - * asin(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - * - * @see http://mathworld.wolfram.com/InverseSine.html - */ - math.asin = function asin(x) { - if (arguments.length != 1) { - throw new util.error.ArgumentsError('asin', arguments.length, 1); - } - - if (isNumber(x)) { - if (x >= -1 && x <= 1) { - return Math.asin(x); - } - else { - return asin(new Complex(x, 0)); - } - } - - if (isComplex(x)) { - // asin(z) = -i*log(iz + sqrt(1-z^2)) - var re = x.re; - var im = x.im; - var temp1 = Complex.create( - im * im - re * re + 1.0, - -2.0 * re * im - ); - - var temp2 = math.sqrt(temp1); - var temp3; - if (temp2 instanceof Complex) { - temp3 = Complex.create( - temp2.re - im, - temp2.im + re - ); - } - else { - temp3 = Complex.create( - temp2 - im, - re - ); - } - - var temp4 = math.log(temp3); - - if (temp4 instanceof Complex) { - return Complex.create(temp4.im, -temp4.re); - } - else { - return Complex.create(0, -temp4); - } - } - - if (isCollection(x)) { - return collection.map(x, asin); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return asin(x.valueOf()); - } - - throw new util.error.UnsupportedTypeError('asin', x); - }; -}; diff --git a/src/function/trigonometry/atan.js b/src/function/trigonometry/atan.js deleted file mode 100644 index 98bd03f49..000000000 --- a/src/function/trigonometry/atan.js +++ /dev/null @@ -1,69 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Complex = require('../../type/Complex.js'), - collection = require('../../type/collection.js'), - - isNumber = util.number.isNumber, - isComplex = Complex.isComplex, - isCollection = collection.isCollection; - - /** - * Calculate the inverse tangent of a value - * - * atan(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - * - * @see http://mathworld.wolfram.com/InverseTangent.html - */ - math.atan = function atan(x) { - if (arguments.length != 1) { - throw new util.error.ArgumentsError('atan', arguments.length, 1); - } - - if (isNumber(x)) { - return Math.atan(x); - } - - if (isComplex(x)) { - // atan(z) = 1/2 * i * (ln(1-iz) - ln(1+iz)) - var re = x.re; - var im = x.im; - var den = re * re + (1.0 - im) * (1.0 - im); - - var temp1 = Complex.create( - (1.0 - im * im - re * re) / den, - (-2.0 * re) / den - ); - var temp2 = math.log(temp1); - - if (temp2 instanceof Complex) { - return Complex.create( - -0.5 * temp2.im, - 0.5 * temp2.re - ); - } - else { - return Complex.create( - 0, - 0.5 * temp2 - ); - } - } - - if (isCollection(x)) { - return collection.map(x, atan); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return atan(x.valueOf()); - } - - throw new util.error.UnsupportedTypeError('atan', x); - }; -}; diff --git a/src/function/trigonometry/atan2.js b/src/function/trigonometry/atan2.js deleted file mode 100644 index 16bbbf4e0..000000000 --- a/src/function/trigonometry/atan2.js +++ /dev/null @@ -1,61 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Complex = require('../../type/Complex.js'), - collection = require('../../type/collection.js'), - - isNumber = util.number.isNumber, - isComplex = Complex.isComplex, - isCollection = collection.isCollection; - - /** - * Computes the principal value of the arc tangent of y/x in radians - * - * atan2(y, x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} y - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - * - * @see http://mathworld.wolfram.com/InverseTangent.html - */ - math.atan2 = function atan2(y, x) { - if (arguments.length != 2) { - throw new util.error.ArgumentsError('atan2', arguments.length, 2); - } - - if (isNumber(y)) { - if (isNumber(x)) { - return Math.atan2(y, x); - } - /* TODO: support for complex computation of atan2 - else if (isComplex(x)) { - return Math.atan2(y.re, x.re); - } - */ - } - else if (isComplex(y)) { - if (isNumber(x)) { - return Math.atan2(y.re, x); - } - /* TODO: support for complex computation of atan2 - else if (isComplex(x)) { - return Math.atan2(y.re, x.re); - } - */ - } - - if (isCollection(y) || isCollection(x)) { - return collection.map2(y, x, atan2); - } - - if (x.valueOf() !== x || y.valueOf() !== y) { - // fallback on the objects primitive values - return atan2(y.valueOf(), x.valueOf()); - } - - throw new util.error.UnsupportedTypeError('atan2', y, x); - }; -}; diff --git a/src/function/trigonometry/cos.js b/src/function/trigonometry/cos.js deleted file mode 100644 index 52f5b2713..000000000 --- a/src/function/trigonometry/cos.js +++ /dev/null @@ -1,60 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Complex = require('../../type/Complex.js'), - Unit = require('../../type/Unit.js'), - collection = require('../../type/collection.js'), - - isNumber = util.number.isNumber, - isComplex = Complex.isComplex, - isUnit = Unit.isUnit, - isCollection = collection.isCollection; - - /** - * Calculate the cosine of a value - * - * cos(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Unit | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - * - * @see http://mathworld.wolfram.com/Cosine.html - */ - math.cos = function cos(x) { - if (arguments.length != 1) { - throw new util.error.ArgumentsError('cos', arguments.length, 1); - } - - if (isNumber(x)) { - return Math.cos(x); - } - - if (isComplex(x)) { - // cos(z) = (exp(iz) + exp(-iz)) / 2 - return Complex.create( - 0.5 * Math.cos(x.re) * (Math.exp(-x.im) + Math.exp(x.im)), - 0.5 * Math.sin(x.re) * (Math.exp(-x.im) - Math.exp(x.im)) - ); - } - - if (isUnit(x)) { - if (!x.hasBase(Unit.BASE_UNITS.ANGLE)) { - throw new TypeError ('Unit in function cos is no angle'); - } - return Math.cos(x.value); - } - - if (isCollection(x)) { - return collection.map(x, cos); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return cos(x.valueOf()); - } - - throw new util.error.UnsupportedTypeError('cos', x); - }; -}; diff --git a/src/function/trigonometry/cot.js b/src/function/trigonometry/cot.js deleted file mode 100644 index b111218aa..000000000 --- a/src/function/trigonometry/cot.js +++ /dev/null @@ -1,60 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Complex = require('../../type/Complex.js'), - Unit = require('../../type/Unit.js'), - collection = require('../../type/collection.js'), - - isNumber = util.number.isNumber, - isComplex = Complex.isComplex, - isUnit = Unit.isUnit, - isCollection = collection.isCollection; - - /** - * Calculate the cotangent of a value. cot(x) is defined as 1 / tan(x) - * - * cot(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Unit | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ - math.cot = function cot(x) { - if (arguments.length != 1) { - throw new util.error.ArgumentsError('cot', arguments.length, 1); - } - - if (isNumber(x)) { - return 1 / Math.tan(x); - } - - if (isComplex(x)) { - var den = Math.exp(-4.0 * x.im) - - 2.0 * Math.exp(-2.0 * x.im) * Math.cos(2.0 * x.re) + 1.0; - - return Complex.create( - 2.0 * Math.exp(-2.0 * x.im) * Math.sin(2.0 * x.re) / den, - (Math.exp(-4.0 * x.im) - 1.0) / den - ); - } - - if (isUnit(x)) { - if (!x.hasBase(Unit.BASE_UNITS.ANGLE)) { - throw new TypeError ('Unit in function cot is no angle'); - } - return 1 / Math.tan(x.value); - } - - if (isCollection(x)) { - return collection.map(x, cot); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return cot(x.valueOf()); - } - - throw new util.error.UnsupportedTypeError('cot', x); - }; -}; diff --git a/src/function/trigonometry/csc.js b/src/function/trigonometry/csc.js deleted file mode 100644 index 46071407c..000000000 --- a/src/function/trigonometry/csc.js +++ /dev/null @@ -1,61 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Complex = require('../../type/Complex.js'), - Unit = require('../../type/Unit.js'), - collection = require('../../type/collection.js'), - - isNumber = util.number.isNumber, - isComplex = Complex.isComplex, - isUnit = Unit.isUnit, - isCollection = collection.isCollection; - - /** - * Calculate the cosecant of a value, csc(x) = 1/sin(x) - * - * csc(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Unit | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ - math.csc = function csc(x) { - if (arguments.length != 1) { - throw new util.error.ArgumentsError('csc', arguments.length, 1); - } - - if (isNumber(x)) { - return 1 / Math.sin(x); - } - - if (isComplex(x)) { - // csc(z) = 1/sin(z) = (2i) / (exp(iz) - exp(-iz)) - var den = 0.25 * (Math.exp(-2.0 * x.im) + Math.exp(2.0 * x.im)) - - 0.5 * Math.cos(2.0 * x.re); - - return Complex.create ( - 0.5 * Math.sin(x.re) * (Math.exp(-x.im) + Math.exp(x.im)) / den, - 0.5 * Math.cos(x.re) * (Math.exp(-x.im) - Math.exp(x.im)) / den - ); - } - - if (isUnit(x)) { - if (!x.hasBase(Unit.BASE_UNITS.ANGLE)) { - throw new TypeError ('Unit in function csc is no angle'); - } - return 1 / Math.sin(x.value); - } - - if (isCollection(x)) { - return collection.map(x, csc); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return csc(x.valueOf()); - } - - throw new util.error.UnsupportedTypeError('csc', x); - }; -}; diff --git a/src/function/trigonometry/sec.js b/src/function/trigonometry/sec.js deleted file mode 100644 index 257407c97..000000000 --- a/src/function/trigonometry/sec.js +++ /dev/null @@ -1,60 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Complex = require('../../type/Complex.js'), - Unit = require('../../type/Unit.js'), - collection = require('../../type/collection.js'), - - isNumber = util.number.isNumber, - isComplex = Complex.isComplex, - isUnit = Unit.isUnit, - isCollection = collection.isCollection; - - /** - * Calculate the secant of a value, sec(x) = 1/cos(x) - * - * sec(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Unit | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ - math.sec = function sec(x) { - if (arguments.length != 1) { - throw new util.error.ArgumentsError('sec', arguments.length, 1); - } - - if (isNumber(x)) { - return 1 / Math.cos(x); - } - - if (isComplex(x)) { - // sec(z) = 1/cos(z) = 2 / (exp(iz) + exp(-iz)) - var den = 0.25 * (Math.exp(-2.0 * x.im) + Math.exp(2.0 * x.im)) + - 0.5 * Math.cos(2.0 * x.re); - return Complex.create( - 0.5 * Math.cos(x.re) * (Math.exp(-x.im) + Math.exp( x.im)) / den, - 0.5 * Math.sin(x.re) * (Math.exp( x.im) - Math.exp(-x.im)) / den - ); - } - - if (isUnit(x)) { - if (!x.hasBase(Unit.BASE_UNITS.ANGLE)) { - throw new TypeError ('Unit in function sec is no angle'); - } - return 1 / Math.cos(x.value); - } - - if (isCollection(x)) { - return collection.map(x, sec); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return sec(x.valueOf()); - } - - throw new util.error.UnsupportedTypeError('sec', x); - }; -}; diff --git a/src/function/trigonometry/sin.js b/src/function/trigonometry/sin.js deleted file mode 100644 index 09dd5545d..000000000 --- a/src/function/trigonometry/sin.js +++ /dev/null @@ -1,59 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Complex = require('../../type/Complex.js'), - Unit = require('../../type/Unit.js'), - collection = require('../../type/collection.js'), - - isNumber = util.number.isNumber, - isComplex = Complex.isComplex, - isUnit = Unit.isUnit, - isCollection = collection.isCollection; - - /** - * Calculate the sine of a value - * - * sin(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Unit | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - * - * @see http://mathworld.wolfram.com/Sine.html - */ - math.sin = function sin(x) { - if (arguments.length != 1) { - throw new util.error.ArgumentsError('sin', arguments.length, 1); - } - - if (isNumber(x)) { - return Math.sin(x); - } - - if (isComplex(x)) { - return Complex.create( - 0.5 * Math.sin(x.re) * (Math.exp(-x.im) + Math.exp( x.im)), - 0.5 * Math.cos(x.re) * (Math.exp( x.im) - Math.exp(-x.im)) - ); - } - - if (isUnit(x)) { - if (!x.hasBase(Unit.BASE_UNITS.ANGLE)) { - throw new TypeError ('Unit in function cos is no angle'); - } - return Math.sin(x.value); - } - - if (isCollection(x)) { - return collection.map(x, sin); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return sin(x.valueOf()); - } - - throw new util.error.UnsupportedTypeError('sin', x); - }; -}; diff --git a/src/function/trigonometry/tan.js b/src/function/trigonometry/tan.js deleted file mode 100644 index fb34aae16..000000000 --- a/src/function/trigonometry/tan.js +++ /dev/null @@ -1,63 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Complex = require('../../type/Complex.js'), - Unit = require('../../type/Unit.js'), - collection = require('../../type/collection.js'), - - isNumber = util.number.isNumber, - isComplex = Complex.isComplex, - isUnit = Unit.isUnit, - isCollection = collection.isCollection; - - /** - * Calculate the tangent of a value - * - * tan(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Unit | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - * - * @see http://mathworld.wolfram.com/Tangent.html - */ - math.tan = function tan(x) { - if (arguments.length != 1) { - throw new util.error.ArgumentsError('tan', arguments.length, 1); - } - - if (isNumber(x)) { - return Math.tan(x); - } - - if (isComplex(x)) { - var den = Math.exp(-4.0 * x.im) + - 2.0 * Math.exp(-2.0 * x.im) * Math.cos(2.0 * x.re) + - 1.0; - - return Complex.create( - 2.0 * Math.exp(-2.0 * x.im) * Math.sin(2.0 * x.re) / den, - (1.0 - Math.exp(-4.0 * x.im)) / den - ); - } - - if (isUnit(x)) { - if (!x.hasBase(Unit.BASE_UNITS.ANGLE)) { - throw new TypeError ('Unit in function tan is no angle'); - } - return Math.tan(x.value); - } - - if (isCollection(x)) { - return collection.map(x, tan); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return tan(x.valueOf()); - } - - throw new util.error.UnsupportedTypeError('tan', x); - }; -}; diff --git a/src/function/units/in.js b/src/function/units/in.js deleted file mode 100644 index bd4f9c153..000000000 --- a/src/function/units/in.js +++ /dev/null @@ -1,47 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Unit = require('../../type/Unit.js'), - collection = require('../../type/collection.js'), - - isString = util.string.isString, - isUnit = Unit.isUnit, - isCollection = collection.isCollection; - - /** - * Change the unit of a value. - * - * x in unit - * in(x, unit) - * - * For matrices, the function is evaluated element wise. - * - * @param {Unit | Array | Matrix} x - * @param {Unit | Array | Matrix} unit - * @return {Unit | Array | Matrix} res - */ - math['in'] = function unit_in(x, unit) { - if (arguments.length != 2) { - throw new util.error.ArgumentsError('in', arguments.length, 2); - } - - if (isUnit(x)) { - if (isUnit(unit) || isString(unit)) { - return x['in'](unit); - } - } - - // TODO: add support for string, in that case, convert to unit - - if (isCollection(x) || isCollection(unit)) { - return collection.map2(x, unit, unit_in); - } - - if (x.valueOf() !== x || unit.valueOf() !== unit) { - // fallback on the objects primitive value - return unit_in(x.valueOf(), unit.valueOf()); - } - - throw new util.error.UnsupportedTypeError('in', x, unit); - }; -}; diff --git a/src/function/utils/clone.js b/src/function/utils/clone.js deleted file mode 100644 index 45cc62b6c..000000000 --- a/src/function/utils/clone.js +++ /dev/null @@ -1,20 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - object = util.object; - - /** - * Clone an object - * - * clone(x) - * - * @param {*} x - * @return {*} clone - */ - math.clone = function clone (x) { - if (arguments.length != 1) { - throw new util.error.ArgumentsError('clone', arguments.length, 1); - } - - return object.clone(x); - }; -}; diff --git a/src/function/utils/eval.js b/src/function/utils/eval.js deleted file mode 100644 index 600d0cd3e..000000000 --- a/src/function/utils/eval.js +++ /dev/null @@ -1,72 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Scope = require('../../expr/Scope.js'), - - collection = require('../../type/collection.js'), - - isString = util.string.isString, - isCollection = collection.isCollection; - - /** - * Evaluate an expression. - * - * Syntax: - * - * math.eval(expr) - * math.eval(expr, scope) - * math.eval([expr1, expr2, expr3, ...]) - * math.eval([expr1, expr2, expr3, ...], scope) - * - * Example: - * - * math.eval('(2+3)/4'); // 1.25 - * math.eval('sqrt(3^2 + 4^2)'); // 5 - * math.eval('sqrt(-4)'); // 2i - * math.eval(['a=3', 'b=4', 'a*b']);, // [3, 4, 12] - * - * var scope = {a:3, b:4}; - * math.eval('a * b', scope); // 12 - * - * @param {String | String[] | Matrix} expr - * @param {Scope | Object} [scope] - * @return {*} res - * @throws {Error} - */ - math.eval = function _eval (expr, scope) { - if (arguments.length != 1 && arguments.length != 2) { - throw new util.error.ArgumentsError('eval', arguments.length, 1, 2); - } - - // instantiate a scope - var evalScope; - if (scope) { - if (scope instanceof Scope) { - evalScope = scope; - } - else { - evalScope = new Scope(math, scope); - } - } - else { - evalScope = new Scope(math); - } - - if (isString(expr)) { - // evaluate a single expression - var node = math.parse(expr, evalScope); - return node.eval(); - } - else if (isCollection(expr)) { - // evaluate an array or matrix with expressions - return collection.map(expr, function (elem) { - var node = math.parse(elem, evalScope); - return node.eval(); - }); - } - else { - // oops - throw new TypeError('String or matrix expected'); - } - }; -}; diff --git a/src/function/utils/format.js b/src/function/utils/format.js deleted file mode 100644 index f6c5263c6..000000000 --- a/src/function/utils/format.js +++ /dev/null @@ -1,32 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - string = util.string; - - /** - * Format a value of any type into a string. Interpolate values into the string. - * Numbers are rounded off to a maximum number of 5 digits by default. - * Usage: - * math.format(value) - * math.format(template, object) - * - * Example usage: - * math.format(2/7); // '0.28571' - * math.format(new Complex(2, 3)); // '2 + 3i' - * math.format('Hello $name! The date is $date', { - * name: 'user', - * date: new Date().toISOString().substring(0, 10) - * }); // 'hello user! The date is 2013-03-23' - * - * @param {String} template - * @param {Object} values - * @return {String} str - */ - math.format = function format (template, values) { - var num = arguments.length; - if (num != 1 && num != 2) { - throw new util.error.ArgumentsError('format', num, 1, 2); - } - - return string.format.apply(string.format, arguments); - }; -}; diff --git a/src/function/utils/help.js b/src/function/utils/help.js deleted file mode 100644 index f1d8642ab..000000000 --- a/src/function/utils/help.js +++ /dev/null @@ -1,58 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Help = require('../../type/Help.js'); - - /** - * Retrieve help on a function or data type. - * Help files are retrieved from the documentation in math.docs. - * @param {function | string | Object} search - * @return {Help} help - */ - math.help = function help(search) { - if (arguments.length != 1) { - throw new SyntaxError('Wrong number of arguments in function help ' + - '(' + arguments.length + ' provided, 1 expected)'); - } - - var text = null; - if ((search instanceof String) || (typeof(search) === 'string')) { - text = search; - } - else { - var prop; - for (prop in math) { - // search in functions and constants - if (math.hasOwnProperty(prop)) { - if (search === math[prop]) { - text = prop; - break; - } - } - } - - if (!text) { - // search data type - for (prop in math.type) { - if (math.type.hasOwnProperty(prop)) { - if (search === math.type[prop]) { - text = prop; - break; - } - } - } - } - } - - if (!text) { - throw new Error('Could not find search term "' + search + '"'); - } - else { - var doc = math.docs[text]; - if (!doc) { - throw new Error('No documentation found on "' + text + '"'); - } - return new Help(math, doc); - } - }; -}; diff --git a/src/function/utils/import.js b/src/function/utils/import.js deleted file mode 100644 index 45c03860f..000000000 --- a/src/function/utils/import.js +++ /dev/null @@ -1,120 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - Complex = require('../../type/Complex.js'), - Unit = require('../../type/Unit.js'), - - isNumber = util.number.isNumber, - isString = util.string.isString, - isComplex = Complex.isComplex, - isUnit = Unit.isUnit; - - /** - * Import functions from an object or a file - * @param {function | String | Object} object - * @param {Object} [options] Available options: - * {Boolean} override - * If true, existing functions will be - * overwritten. False by default. - * {Boolean} wrap - * If true (default), the functions will - * be wrapped in a wrapper function which - * converts data types like Matrix to - * primitive data types like Array. - * The wrapper is needed when extending - * math.js with libraries which do not - * support the math.js data types. - */ -// TODO: return status information - math['import'] = function math_import(object, options) { - var name; - var opts = { - override: false, - wrap: true - }; - if (options && options instanceof Object) { - util.object.extend(opts, options); - } - - if (isString(object)) { - // a string with a filename - if (typeof (require) !== 'undefined') { - // load the file using require - var _module = require(object); - math_import(_module); - } - else { - throw new Error('Cannot load file: require not available.'); - } - } - else if (isSupportedType(object)) { - // a single function - name = object.name; - if (name) { - if (opts.override || math[name] === undefined) { - _import(name, object, opts); - } - } - else { - throw new Error('Cannot import an unnamed function or object'); - } - } - else if (object instanceof Object) { - // a map with functions - for (name in object) { - if (object.hasOwnProperty(name)) { - var value = object[name]; - if (isSupportedType(value)) { - _import(name, value, opts); - } - else { - math_import(value); - } - } - } - } - }; - - /** - * Add a property to the math namespace and create a chain proxy for it. - * @param {String} name - * @param {*} value - * @param {Object} options See import for a description of the options - * @private - */ - function _import(name, value, options) { - if (options.override || math[name] === undefined) { - // add to math namespace - if (options.wrap && typeof value === 'function') { - // create a wrapper around the function - math[name] = function () { - var args = []; - for (var i = 0, len = arguments.length; i < len; i++) { - args[i] = arguments[i].valueOf(); - } - return value.apply(math, args); - }; - } - else { - // just create a link to the function or value - math[name] = value; - } - - // create a proxy for the Selector - math.expr.Selector.createProxy(name, value); - } - } - - /** - * Check whether given object is a supported type - * @param object - * @return {Boolean} - * @private - */ - function isSupportedType(object) { - return (typeof object == 'function') || - isNumber(object) || isString(object) || - isComplex(object) || isUnit(object); - // TODO: add boolean? - } -}; diff --git a/src/function/utils/parse.js b/src/function/utils/parse.js deleted file mode 100644 index f1ea89037..000000000 --- a/src/function/utils/parse.js +++ /dev/null @@ -1,1334 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'), - - isString = util.string.isString, - isArray = Array.isArray, - - // types - Complex = require('./../../type/Complex.js'), - Matrix = require('./../../type/Matrix.js'), - Unit = require('./../../type/Unit.js'), - Range = require('./../../type/Range.js'), - collection = require('../../type/collection.js'), - - // scope and nodes - Scope = require('./../../expr/Scope.js'), - AssignmentNode = require('../../expr/node/AssignmentNode.js'), - BlockNode = require('../../expr/node/BlockNode.js'), - ConstantNode = require('../../expr/node/ConstantNode.js'), - FunctionNode = require('../../expr/node/FunctionNode.js'), - MatrixNode = require('../../expr/node/MatrixNode.js'), - OperatorNode = require('../../expr/node/OperatorNode.js'), - ParamsNode = require('../../expr/node/ParamsNode.js'), - SymbolNode = require('../../expr/node/SymbolNode.js'), - UpdateNode = require('../../expr/node/UpdateNode.js'), - handlers = require('../../expr/node/handlers.js'); - - /** - * Parse an expression. Returns a node tree, which can be evaluated by - * invoking node.eval(); - * - * Syntax: - * - * math.parse(expr) - * math.parse(expr, scope) - * math.parse([expr1, expr2, expr3, ...]) - * math.parse([expr1, expr2, expr3, ...], scope) - * - * Example: - * - * var node = math.parse('sqrt(3^2 + 4^2)'); - * node.eval(); // 5 - * - * var scope = {a:3, b:4} - * var node = math.parse('a * b', scope); // 12 - * node.eval(); // 12 - * scope.a = 5; - * node.eval(); // 20 - * - * var nodes = math.parse(['a = 3', 'b = 4', 'a * b']); - * nodes[2].eval(); // 12 - * - * @param {String | String[] | Matrix} expr - * @param {Scope | Object} [scope] - * @return {Node | Node[]} node - * @throws {Error} - */ - math.parse = function parse (expr, scope) { - if (arguments.length != 1 && arguments.length != 2) { - throw new util.error.ArgumentsError('parse', arguments.length, 1, 2); - } - - // instantiate a scope - var parseScope; - if (scope) { - if (scope instanceof Scope) { - parseScope = scope; - } - else { - parseScope = new Scope(math, scope); - } - } - else { - parseScope = new Scope(math); - } - - if (isString(expr)) { - // parse a single expression - expression = expr || ''; - return parseStart(parseScope); - } - else if (isArray(expr) || expr instanceof Matrix) { - // parse an array or matrix with expressions - return collection.map(expr, function (elem) { - expression = elem || ''; - return parseStart(parseScope); - }); - } - else { - // oops - throw new TypeError('String or matrix expected'); - } - }; - -// token types enumeration - var TOKENTYPE = { - NULL : 0, - DELIMITER : 1, - NUMBER : 2, - SYMBOL : 3, - UNKNOWN : 4 - }; - -// map with all delimiters - var DELIMITERS = { - ',': true, - '(': true, - ')': true, - '[': true, - ']': true, - '\"': true, - '\n': true, - ';': true, - - '+': true, - '-': true, - '*': true, - '.*': true, - '/': true, - './': true, - '%': true, - '^': true, - '.^': true, - '!': true, - '\'': true, - '=': true, - ':': true, - - '==': true, - '!=': true, - '<': true, - '>': true, - '<=': true, - '>=': true - }; - - var expression = ''; // current expression - var index = 0; // current index in expr - var c = ''; // current token character in expr - var token = ''; // current token - var token_type = TOKENTYPE.NULL; // type of the token - - /** - * Get the first character from the expression. - * The character is stored into the char c. If the end of the expression is - * reached, the function puts an empty string in c. - * @private - */ - function first() { - index = 0; - c = expression.charAt(0); - } - - /** - * Get the next character from the expression. - * The character is stored into the char c. If the end of the expression is - * reached, the function puts an empty string in c. - * @private - */ - function next() { - index++; - c = expression.charAt(index); - } - - /** - * Preview the next character from the expression. - * @return {String} cNext - * @private - */ - function nextPreview() { - return expression.charAt(index + 1); - } - - /** - * Get next token in the current string expr. - * The token and token type are available as token and token_type - * @private - */ - function getToken() { - token_type = TOKENTYPE.NULL; - token = ''; - - // skip over whitespaces - while (c == ' ' || c == '\t') { // space or tab - next(); - } - - // skip comment - if (c == '#') { - while (c != '\n' && c != '') { - next(); - } - } - - // check for end of expression - if (c == '') { - // token is still empty - token_type = TOKENTYPE.DELIMITER; - return; - } - - // check for delimiters consisting of 2 characters - var c2 = c + nextPreview(); - if (DELIMITERS[c2]) { - token_type = TOKENTYPE.DELIMITER; - token = c2; - next(); - next(); - return; - } - - // check for delimiters consisting of 1 character - if (DELIMITERS[c]) { - token_type = TOKENTYPE.DELIMITER; - token = c; - next(); - return; - } - - // check for a number - if (isDigitDot(c)) { - token_type = TOKENTYPE.NUMBER; - - // get number, can have a single dot - if (c == '.') { - token += c; - next(); - - if (!isDigit(c)) { - // this is no legal number, it is just a dot - token_type = TOKENTYPE.UNKNOWN; - } - } - else { - while (isDigit(c)) { - token += c; - next(); - } - if (c == '.') { - token += c; - next(); - } - } - while (isDigit(c)) { - token += c; - next(); - } - - // check for scientific notation like "2.3e-4" or "1.23e50" - if (c == 'E' || c == 'e') { - token += c; - next(); - - if (c == '+' || c == '-') { - token += c; - next(); - } - - // Scientific notation MUST be followed by an exponent - if (!isDigit(c)) { - // this is no legal number, exponent is missing. - token_type = TOKENTYPE.UNKNOWN; - } - - while (isDigit(c)) { - token += c; - next(); - } - } - - return; - } - - // check for variables or functions - if (isAlpha(c)) { - token_type = TOKENTYPE.SYMBOL; - - while (isAlpha(c) || isDigit(c)) { - token += c; - next(); - } - return; - } - - // something unknown is found, wrong characters -> a syntax error - token_type = TOKENTYPE.UNKNOWN; - while (c != '') { - token += c; - next(); - } - throw createSyntaxError('Syntax error in part "' + token + '"'); - } - - /** - * Check if a given name is valid - * if not, an error is thrown - * @param {String} name - * @return {boolean} valid - * @private - */ - // TODO: check for valid symbol name - function isValidSymbolName (name) { - for (var i = 0, iMax = name.length; i < iMax; i++) { - var c = name.charAt(i); - //var valid = (isAlpha(c) || (i > 0 && isDigit(c))); // TODO: allow digits in symbol name - var valid = (isAlpha(c)); - if (!valid) { - return false; - } - } - - return true; - } - - /** - * checks if the given char c is a letter (upper or lower case) - * or underscore - * @param {String} c a string with one character - * @return {Boolean} - * @private - */ - function isAlpha (c) { - return ((c >= 'a' && c <= 'z') || - (c >= 'A' && c <= 'Z') || - c == '_'); - } - - /** - * checks if the given char c is a digit or dot - * @param {String} c a string with one character - * @return {Boolean} - * @private - */ - function isDigitDot (c) { - return ((c >= '0' && c <= '9') || - c == '.'); - } - - /** - * checks if the given char c is a digit - * @param {String} c a string with one character - * @return {Boolean} - * @private - */ - function isDigit (c) { - return ((c >= '0' && c <= '9')); - } - - /** - * Start of the parse levels below, in order of precedence - * @param {Scope} scope - * @return {Node} node - * @private - */ - function parseStart (scope) { - // get the first character in expression - first(); - - getToken(); - - var node; - if (token == '') { - // empty expression - node = new ConstantNode(undefined); - } - else { - node = parseBlock(scope); - } - - // check for garbage at the end of the expression - // an expression ends with a empty character '' and token_type DELIMITER - if (token != '') { - if (token_type == TOKENTYPE.DELIMITER) { - // user entered a not existing operator like "//" - - // TODO: give hints for aliases, for example with "<>" give as hint " did you mean != ?" - throw createError('Unknown operator ' + token); - } - else { - throw createSyntaxError('Unexpected part "' + token + '"'); - } - } - - return node; - } - - /** - * Parse a block with expressions. Expressions can be separated by a newline - * character '\n', or by a semicolon ';'. In case of a semicolon, no output - * of the preceding line is returned. - * @param {Scope} scope - * @return {Node} node - * @private - */ - function parseBlock (scope) { - var node, block, visible; - - if (token != '\n' && token != ';' && token != '') { - node = parseAns(scope); - } - - while (token == '\n' || token == ';') { - if (!block) { - // initialize the block - block = new BlockNode(); - if (node) { - visible = (token != ';'); - block.add(node, visible); - } - } - - getToken(); - if (token != '\n' && token != ';' && token != '') { - node = parseAns(scope); - - visible = (token != ';'); - block.add(node, visible); - } - } - - if (block) { - return block; - } - - if (!node) { - node = parseAns(scope); - } - - return node; - } - - /** - * Parse assignment of ans. - * Ans is assigned when the expression itself is no variable or function - * assignment - * @param {Scope} scope - * @return {Node} node - * @private - */ - function parseAns (scope) { - var expression = parseFunctionAssignment(scope); - - // create a variable definition for ans - var name = 'ans'; - return new AssignmentNode(name, expression, scope); - } - - /** - * Parse a function assignment like "function f(a,b) = a*b" - * @param {Scope} scope - * @return {Node} node - * @private - */ - function parseFunctionAssignment (scope) { - // TODO: keyword 'function' must become a reserved keyword - // TODO: replace the 'function' keyword with an assignment operator '=>' - if (token_type == TOKENTYPE.SYMBOL && token == 'function') { - // get function name - getToken(); - if (token_type != TOKENTYPE.SYMBOL) { - throw createSyntaxError('Function name expected'); - } - var name = token; - - // get parenthesis open - getToken(); - if (token != '(') { - throw createSyntaxError('Opening parenthesis ( expected'); - } - - // get function variables - var functionScope = scope.createSubScope(); - var variables = []; - while (true) { - getToken(); - if (token_type == TOKENTYPE.SYMBOL) { - // store variable name - variables.push(token); - } - else { - throw createSyntaxError('Variable name expected'); - } - - getToken(); - if (token == ',') { - // ok, nothing to do, read next variable - } - else if (token == ')') { - // end of variable list encountered. break loop - break; - } - else { - throw createSyntaxError('Comma , or closing parenthesis ) expected"'); - } - } - - getToken(); - if (token != '=') { - throw createSyntaxError('Equal sign = expected'); - } - - // parse the expression, with the correct function scope - getToken(); - var expression = parseAssignment(functionScope); - - return new FunctionNode(name, variables, expression, functionScope, scope); - } - - return parseAssignment(scope); - } - - /** - * Assignment of a variable, can be a variable like "a=2.3" or a updating an - * existing variable like "matrix(2,3:5)=[6,7,8]" - * @param {Scope} scope - * @return {Node} node - * @private - */ - function parseAssignment (scope) { - var name, params, paramScopes, expr; - - var node = parseRange(scope); - - if (token == '=') { - if (node instanceof SymbolNode) { - // parse the expression, with the correct function scope - getToken(); - name = node.name; - params = null; - expr = parseAssignment(scope); - return new AssignmentNode(name, expr, scope); - } - else if (node instanceof ParamsNode && node.object instanceof SymbolNode) { - // parse the expression, with the correct function scope - getToken(); - name = node.object.name; - params = node.params; - paramScopes = node.paramScopes; - expr = parseAssignment(scope); - return new UpdateNode(math, name, params, paramScopes, expr, scope); - } - else { - throw createSyntaxError('Symbol expected at the left hand side ' + - 'of assignment operator ='); - } - } - - return node; - } - - /** - * parse range, "start:end", "start:step:end", ":", "start:", ":end", etc - * @param {Scope} scope - * @return {Node} node - * @private - */ - function parseRange (scope) { - var node, name, fn, params = []; - - if (token == ':') { - // implicit start=0 - node = new ConstantNode(0); - } - else { - // explicit start - node = parseConditions(scope); - } - - if (token == ':') { - params.push(node); - - // parse step and end - while (token == ':') { - getToken(); - if (token == ')' || token == ',' || token == '') { - // implicit end - params.push(new SymbolNode('end', scope)); - } - else { - // explicit end - params.push(parseConditions(scope)); - } - } - - if (params.length) { - // create a range constructor - name = ':'; - fn = math.range; - - if (params.length >= 3) { - // swap step and end - var step = params[2]; - params[2] = params[1]; // end - params[1] = step; - } - - node = new OperatorNode(name, fn, params); - } - } - - return node; - } - - /** - * conditions like and, or, in - * @param {Scope} scope - * @return {Node} node - * @private - */ - function parseConditions (scope) { - var node, operators, name, fn, params; - - node = parseBitwiseConditions(scope); - - // TODO: precedence of And above Or? - // TODO: implement a method for unit to number conversion - operators = { - 'in' : math['in'] - /* TODO: implement conditions - 'and' : 'and', - '&&' : 'and', - 'or': 'or', - '||': 'or', - 'xor': 'xor' - */ - }; - - while (operators[token] !== undefined) { - name = token; - fn = operators[name]; - - getToken(); - params = [node, parseBitwiseConditions(scope)]; - node = new OperatorNode(name, fn, params); - } - - return node; - } - - /** - * conditional operators and bitshift - * @param {Scope} scope - * @return {Node} node - * @private - */ - function parseBitwiseConditions (scope) { - var node = parseComparison(scope); - - /* TODO: implement bitwise conditions - var operators = { - '&' : bitwiseand, - '|' : bitwiseor, - // todo: bitwise xor? - '<<': bitshiftleft, - '>>': bitshiftright - }; - while (operators[token] !== undefined) { - var name = token; - var fn = operators[name]; - - getToken(); - var params = [node, parseComparison()]; - node = new OperatorNode(name, fn, params); - } - */ - - return node; - } - - /** - * comparison operators - * @param {Scope} scope - * @return {Node} node - * @private - */ - function parseComparison (scope) { - var node, operators, name, fn, params; - - node = parseAddSubtract(scope); - - operators = { - '==': math.equal, - '!=': math.unequal, - '<': math.smaller, - '>': math.larger, - '<=': math.smallereq, - '>=': math.largereq - }; - while (operators[token] !== undefined) { - name = token; - fn = operators[name]; - - getToken(); - params = [node, parseAddSubtract(scope)]; - node = new OperatorNode(name, fn, params); - } - - return node; - } - - /** - * add or subtract - * @param {Scope} scope - * @return {Node} node - * @private - */ - function parseAddSubtract (scope) { - var node, operators, name, fn, params; - - node = parseMultiplyDivide(scope); - - operators = { - '+': math.add, - '-': math.subtract - }; - while (operators[token] !== undefined) { - name = token; - fn = operators[name]; - - getToken(); - params = [node, parseMultiplyDivide(scope)]; - node = new OperatorNode(name, fn, params); - } - - return node; - } - - /** - * multiply, divide, modulus - * @param {Scope} scope - * @return {Node} node - * @private - */ - function parseMultiplyDivide (scope) { - var node, operators, name, fn, params; - - node = parseUnary(scope); - - operators = { - '*': math.multiply, - '.*': math.emultiply, - '/': math.divide, - './': math.edivide, - '%': math.mod, - 'mod': math.mod - }; - - while (operators[token] !== undefined) { - name = token; - fn = operators[name]; - - getToken(); - params = [node, parseUnary(scope)]; - node = new OperatorNode(name, fn, params); - } - - return node; - } - - /** - * Unary minus - * @param {Scope} scope - * @return {Node} node - * @private - */ - function parseUnary (scope) { - var name, fn, params; - - if (token == '-') { - name = token; - fn = math.unary; - getToken(); - params = [parseUnary(scope)]; - - return new OperatorNode(name, fn, params); - } - - return parsePow(scope); - } - - /** - * power - * Node: power operator is right associative - * @param {Scope} scope - * @return {Node} node - * @private - */ - function parsePow (scope) { - var node, leftNode, nodes, ops, name, fn, params; - - nodes = [ - parseFactorial(scope) - ]; - ops = []; - - // stack all operands of a chained power operator (like '2^3^3') - while (token == '^' || token == '.^') { - ops.push(token); - getToken(); - nodes.push(parseFactorial(scope)); - } - - // evaluate the operands from right to left (right associative) - node = nodes.pop(); - while (nodes.length) { - leftNode = nodes.pop(); - name = ops.pop(); - fn = (name == '^') ? math.pow : math.epow; - params = [leftNode, node]; - node = new OperatorNode(name, fn, params); - } - - return node; - } - - /** - * Factorial - * @param {Scope} scope - * @return {Node} node - * @private - */ - function parseFactorial (scope) { - var node, name, fn, params; - - node = parseTranspose(scope); - - while (token == '!') { - name = token; - fn = math.factorial; - getToken(); - params = [node]; - - node = new OperatorNode(name, fn, params); - } - - return node; - } - - /** - * Transpose - * @param {Scope} scope - * @return {Node} node - * @private - */ - function parseTranspose (scope) { - var node, name, fn, params; - - node = parseNodeHandler(scope); - - while (token == '\'') { - name = token; - fn = math.transpose; - getToken(); - params = [node]; - - node = new OperatorNode(name, fn, params); - } - - return node; - } - - /** - * Parse a custom node handler. A node handler can be used to process - * nodes in a custom way, for example for handling a plot. - * - * A handler must be defined in the namespace math.expr.node.handlers, - * and must extend math.expr.node.Node, and the handler must contain - * functions eval(), find(filter), and toString(). - * - * For example: - * - * math.expr.node.handlers['plot'] = PlotHandler; - * - * The constructor of the handler is called as: - * - * node = new PlotHandler(params, paramScopes); - * - * The handler will be invoked when evaluating an expression like: - * - * node = math.parse('plot(sin(x), x)'); - * - * @param {Scope} scope - * @return {Node} node - * @private - */ - function parseNodeHandler (scope) { - var params, - paramScopes, - paramScope, - handler; - - if (token_type == TOKENTYPE.SYMBOL && handlers[token]) { - handler = handlers[token]; - - getToken(); - - // parse parameters - if (token == '(') { - params = []; - paramScopes = []; - - getToken(); - - if (token != ')') { - paramScope = scope.createSubScope(); - paramScopes.push(paramScope); - params.push(parseRange(paramScope)); - - // parse a list with parameters - while (token == ',') { - getToken(); - - paramScope = scope.createSubScope(); - paramScopes.push(paramScope); - params.push(parseRange(paramScope)); - } - } - - if (token != ')') { - throw createSyntaxError('Parenthesis ) expected'); - } - getToken(); - } - - // create a new node handler - //noinspection JSValidateTypes - return new handler(params, paramScopes); - } - - return parseSymbol(scope); - } - - /** - * parse symbols: functions, variables, constants, units - * @param {Scope} scope - * @return {Node} node - * @private - */ - function parseSymbol (scope) { - var node, name; - - if (token_type == TOKENTYPE.SYMBOL) { - name = token; - - getToken(); - - // create a symbol - node = new SymbolNode(name, scope); - - // parse parameters - return parseParams(scope, node); - } - - return parseString(scope); - } - - /** - * parse parameters, enclosed in parenthesis - * @param {Scope} scope - * @param {Node} node Node on which to apply the parameters. If there - * are no parameters in the expression, the node - * itself is returned - * @return {Node} node - * @private - */ - function parseParams (scope, node) { - var params, - paramScopes, - paramScope; - - while (token == '(') { - params = []; - paramScopes = []; - - getToken(); - - if (token != ')') { - paramScope = scope.createSubScope(); - paramScopes.push(paramScope); - params.push(parseRange(paramScope)); - - // parse a list with parameters - while (token == ',') { - getToken(); - - paramScope = scope.createSubScope(); - paramScopes.push(paramScope); - params.push(parseRange(paramScope)); - } - } - - if (token != ')') { - throw createSyntaxError('Parenthesis ) expected'); - } - getToken(); - - node = new ParamsNode(math, node, params, paramScopes); - } - - return node; - } - - /** - * parse a string. - * A string is enclosed by double quotes - * @param {Scope} scope - * @return {Node} node - * @private - */ - function parseString (scope) { - var node, str, tPrev; - - if (token == '"') { - // string "..." - str = ''; - tPrev = ''; - while (c != '' && (c != '\"' || tPrev == '\\')) { // also handle escape character - str += c; - tPrev = c; - next(); - } - - getToken(); - if (token != '"') { - throw createSyntaxError('End of string " expected'); - } - getToken(); - - // create constant - node = new ConstantNode(str); - - // parse parameters - node = parseParams(scope, node); - - return node; - } - - return parseMatrix(scope); - } - - /** - * parse the matrix - * @param {Scope} scope - * @return {Node} A MatrixNode - * @private - */ - function parseMatrix (scope) { - var array, params, r, c, rows, cols; - - if (token == '[') { - // matrix [...] - - // skip newlines - getToken(); - while (token == '\n') { - getToken(); - } - - // check if this is an empty matrix "[ ]" - if (token != ']') { - // this is a non-empty matrix - params = []; - r = 0; - c = 0; - - params[0] = [parseAssignment(scope)]; - - // the columns in the matrix are separated by commas, and the rows by dot-comma's - while (token == ',' || token == ';') { - if (token == ',') { - c++; - } - else { - r++; - c = 0; - params[r] = []; - } - - // skip newlines - getToken(); - while (token == '\n') { - getToken(); - } - - params[r][c] = parseAssignment(scope); - - // skip newlines - while (token == '\n') { - getToken(); - } - } - - // TODO: spaces as separator for matrix columns - /* - // the columns in the matrix are separated by commas or spaces, - // and the rows by dot-comma's - while (token && token != ']') { - if (token == ';') { - r++; - c = 0; - params[r] = []; - getToken(); - } - else if (token == ',') { - c++; - getToken(); - } - else { - c++; - } - - // skip newlines - while (token == '\n') { - getToken(); - } - - //TODO: math.eval('[1 -2 3]') is evaluated as '[(1-2) 3]' instead of '[(1) (-2) (3)]' - //TODO: '[(1) (-2) (3)]' doesn't work - params[r][c] = parseAssignment(scope); - - // skip newlines - while (token == '\n') { - getToken(); - } - } - */ - - rows = params.length; - cols = (params.length > 0) ? params[0].length : 0; - - // check if the number of columns matches in all rows - for (r = 1; r < rows; r++) { - if (params[r].length != cols) { - throw createError('Number of columns must match ' + - '(' + params[r].length + ' != ' + cols + ')'); - } - } - - if (token != ']') { - throw createSyntaxError('End of matrix ] expected'); - } - - getToken(); - array = new MatrixNode(params); - } - else { - // this is an empty matrix "[ ]" - getToken(); - array = new MatrixNode([]); - } - - // parse parameters - array = parseParams(scope, array); - - return array; - } - - return parseNumber(scope); - } - - /** - * parse a number - * @param {Scope} scope - * @return {Node} node - * @private - */ - function parseNumber (scope) { - var node, value, number; - - if (token_type == TOKENTYPE.NUMBER) { - // this is a number - if (token == '.') { - number = 0; - } else { - number = Number(token); - } - getToken(); - - /* TODO: implicit multiplication? - // TODO: how to calculate a=3; 2/2a ? is this (2/2)*a or 2/(2*a) ? - // check for implicit multiplication - if (token_type == TOKENTYPE.VARIABLE) { - node = multiply(node, parsePow()); - } - //*/ - - if (token_type == TOKENTYPE.SYMBOL) { - if (token == 'i' || token == 'I') { - value = new Complex(0, number); - getToken(); - return new ConstantNode(value); - } - - if (Unit.isPlainUnit(token)) { - value = new Unit(number, token); - getToken(); - return new ConstantNode(value); - } - - throw createTypeError('Unknown unit "' + token + '"'); - } - - // just a regular number - node = new ConstantNode(number); - - // parse parameters - node = parseParams(scope, node); - - return node; - } - - return parseParentheses(scope); - } - - /** - * parentheses - * @param {Scope} scope - * @return {Node} node - * @private - */ - function parseParentheses (scope) { - var node; - - // check if it is a parenthesized expression - if (token == '(') { - // parentheses (...) - getToken(); - node = parseAssignment(scope); // start again - - if (token != ')') { - throw createSyntaxError('Parenthesis ) expected'); - } - getToken(); - - /* TODO: implicit multiplication? - // TODO: how to calculate a=3; 2/2a ? is this (2/2)*a or 2/(2*a) ? - // check for implicit multiplication - if (token_type == TOKENTYPE.VARIABLE) { - node = multiply(node, parsePow()); - } - //*/ - - // parse parameters - node = parseParams(scope, node); - - return node; - } - - return parseEnd(scope); - } - - /** - * Evaluated when the expression is not yet ended but expected to end - * @param {Scope} scope - * @return {Node} res - * @private - */ - function parseEnd (scope) { - if (token == '') { - // syntax error or unexpected end of expression - throw createSyntaxError('Unexpected end of expression'); - } else { - throw createSyntaxError('Value expected'); - } - } - - /** - * Shortcut for getting the current row value (one based) - * Returns the line of the currently handled expression - * @private - */ - function row () { - // TODO: also register row number during parsing - return undefined; - } - - /** - * Shortcut for getting the current col value (one based) - * Returns the column (position) where the last token starts - * @private - */ - function col () { - return index - token.length + 1; - } - - /** - * Build up an error message - * @param {String} message - * @return {String} message with row and column information - * @private - */ - function createErrorMessage (message) { - var r = row(); - var c = col(); - if (r === undefined) { - if (c === undefined) { - return message; - } else { - return message + ' (char ' + c + ')'; - } - } else { - return message + ' (line ' + r + ', char ' + c + ')'; - } - } - - /** - * Create an error - * @param {String} message - * @return {SyntaxError} instantiated error - * @private - */ - function createSyntaxError (message) { - return new SyntaxError(createErrorMessage(message)); - } - - /** - * Create an error - * @param {String} message - * @return {TypeError} instantiated error - * @private - */ - function createTypeError(message) { - return new TypeError(createErrorMessage(message)); - } - - /** - * Create an error - * @param {String} message - * @return {Error} instantiated error - * @private - */ - function createError (message) { - return new Error(createErrorMessage(message)); - } -}; diff --git a/src/function/utils/select.js b/src/function/utils/select.js deleted file mode 100644 index 4ff1b9654..000000000 --- a/src/function/utils/select.js +++ /dev/null @@ -1,40 +0,0 @@ -module.exports = function (math) { - /** - * Wrap any value in a Selector, allowing to perform chained operations on - * the value. - * - * All methods available in the math.js library can be called upon the selector, - * and then will be evaluated with the value itself as first argument. - * The selector can be closed by executing selector.done(), which will return - * the final value. - * - * Example usage: - * math.select(3) - * .add(4) - * .subtract(2) - * .done(); // 5 - * math.select( [[1, 2], [3, 4]] ) - * .set([1, 1], 8) - * .multiply(3) - * .done(); // [[24, 6], [9, 12]] - * - * The Selector has a number of special functions: - * - done() Finalize the chained operation and return the selectors value. - * - valueOf() The same as done() - * - toString() Executes math.format() onto the selectors value, returning - * a string representation of the value. - * - get(...) Get a subselection of the selectors value. Only applicable when - * the value has a method get, for example when value is a Matrix - * or Array. - * - set(...) Replace a subselection of the selectors value. Only applicable - * when the value has a method get, for example when value is a - * Matrix or Array. - * - * @param {*} value - * @return {math.expr.Selector} selector - */ - math.select = function select(value) { - // TODO: check number of arguments - return new math.expr.Selector(value); - }; -}; diff --git a/src/function/utils/typeof.js b/src/function/utils/typeof.js deleted file mode 100644 index d9ca56e2e..000000000 --- a/src/function/utils/typeof.js +++ /dev/null @@ -1,20 +0,0 @@ -module.exports = function (math) { - var util = require('../../util/index.js'); - - /** - * Determine the type of a variable - * - * typeof(x) - * - * @param {*} x - * @return {String} type Lower case type, for example "number", "string", - * "array". - */ - math['typeof'] = function _typeof (x) { - if (arguments.length != 1) { - throw new util.error.ArgumentsError('typeof', arguments.length, 1); - } - - return util.types.type(x); - }; -}; diff --git a/src/header.js b/src/header.js deleted file mode 100644 index 5bfcef3ad..000000000 --- a/src/header.js +++ /dev/null @@ -1,26 +0,0 @@ -/** - * math.js - * https://github.com/josdejong/mathjs - * - * Math.js is an extensive math library for JavaScript and Node.js, - * It features real and complex numbers, units, matrices, a large set of - * mathematical functions, and a flexible expression parser. - * - * @version @@version - * @date @@date - * - * @license - * Copyright (C) 2013 Jos de Jong - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy - * of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ diff --git a/src/index.js b/src/index.js deleted file mode 100644 index 937e0ef40..000000000 --- a/src/index.js +++ /dev/null @@ -1,116 +0,0 @@ -// options (global configuration settings) -exports.options = require('./options'); - -// expression (Parser, Scope, Nodes) -exports.expr = {}; -exports.expr.node = require('./expr/node/index.js'); -exports.expr.Scope = require('./expr/Scope.js'); -exports.expr.Parser = require('./expr/Parser.js'); - -// types (Matrix, Complex, Unit, ...) -exports.type = require('./type/index.js'); - -// docs -exports.docs = require('./docs/index.js'); - -// functions - arithmetic -require('./function/arithmetic/abs.js')(exports); -require('./function/arithmetic/add.js')(exports); -require('./function/arithmetic/add.js')(exports); -require('./function/arithmetic/ceil.js')(exports); -require('./function/arithmetic/cube.js')(exports); -require('./function/arithmetic/divide.js')(exports); -require('./function/arithmetic/edivide.js')(exports); -require('./function/arithmetic/emultiply.js')(exports); -require('./function/arithmetic/epow.js')(exports); -require('./function/arithmetic/equal.js')(exports); -require('./function/arithmetic/exp.js')(exports); -require('./function/arithmetic/fix.js')(exports); -require('./function/arithmetic/floor.js')(exports); -require('./function/arithmetic/gcd.js')(exports); -require('./function/arithmetic/larger.js')(exports); -require('./function/arithmetic/largereq.js')(exports); -require('./function/arithmetic/lcm.js')(exports); -require('./function/arithmetic/log.js')(exports); -require('./function/arithmetic/log10.js')(exports); -require('./function/arithmetic/mod.js')(exports); -require('./function/arithmetic/multiply.js')(exports); -require('./function/arithmetic/pow.js')(exports); -require('./function/arithmetic/round.js')(exports); -require('./function/arithmetic/sign.js')(exports); -require('./function/arithmetic/smaller.js')(exports); -require('./function/arithmetic/smallereq.js')(exports); -require('./function/arithmetic/sqrt.js')(exports); -require('./function/arithmetic/square.js')(exports); -require('./function/arithmetic/subtract.js')(exports); -require('./function/arithmetic/unary.js')(exports); -require('./function/arithmetic/unequal.js')(exports); -require('./function/arithmetic/xgcd.js')(exports); - -// functions - complex -require('./function/complex/arg.js')(exports); -require('./function/complex/conj.js')(exports); -require('./function/complex/re.js')(exports); -require('./function/complex/im.js')(exports); - -// functions - construction -require('./function/construction/boolean.js')(exports); -require('./function/construction/complex.js')(exports); -require('./function/construction/matrix.js')(exports); -require('./function/construction/number.js')(exports); -require('./function/construction/parser.js')(exports); -require('./function/construction/range.js')(exports); -require('./function/construction/string.js')(exports); -require('./function/construction/unit.js')(exports); - -// functions - matrix -require('./function/matrix/concat.js')(exports); -require('./function/matrix/det.js')(exports); -require('./function/matrix/diag.js')(exports); -require('./function/matrix/eye.js')(exports); -require('./function/matrix/inv.js')(exports); -require('./function/matrix/ones.js')(exports); -require('./function/matrix/size.js')(exports); -require('./function/matrix/squeeze.js')(exports); -require('./function/matrix/subset.js')(exports); -require('./function/matrix/transpose.js')(exports); -require('./function/matrix/zeros.js')(exports); - -// functions - probability -require('./function/probability/factorial.js')(exports); -require('./function/probability/random.js')(exports); - -// functions - statistics -require('./function/statistics/min.js')(exports); -require('./function/statistics/max.js')(exports); - -// functions - trigonometry -require('./function/trigonometry/acos.js')(exports); -require('./function/trigonometry/asin.js')(exports); -require('./function/trigonometry/atan.js')(exports); -require('./function/trigonometry/atan2.js')(exports); -require('./function/trigonometry/cos.js')(exports); -require('./function/trigonometry/cot.js')(exports); -require('./function/trigonometry/csc.js')(exports); -require('./function/trigonometry/sec.js')(exports); -require('./function/trigonometry/sin.js')(exports); -require('./function/trigonometry/tan.js')(exports); - -// functions - units -require('./function/units/in.js')(exports); - -// functions - utils -require('./function/utils/clone.js')(exports); -require('./function/utils/eval.js')(exports); -require('./function/utils/format.js')(exports); -require('./function/utils/help.js')(exports); -require('./function/utils/import.js')(exports); -require('./function/utils/parse.js')(exports); -require('./function/utils/select.js')(exports); -require('./function/utils/typeof.js')(exports); - -// constants -require('./constants.js')(exports); - -// selector (we initialize after all functions are loaded) -exports.expr.Selector = require('./expr/Selector.js')(exports); diff --git a/src/options.js b/src/options.js deleted file mode 100644 index 957acc966..000000000 --- a/src/options.js +++ /dev/null @@ -1,2 +0,0 @@ -// math.js options -exports.precision = 5; // number of digits in formatted output diff --git a/src/shim.js b/src/shim.js deleted file mode 100644 index 88289382b..000000000 --- a/src/shim.js +++ /dev/null @@ -1,183 +0,0 @@ -/** - * Compatibility shims for legacy JavaScript engines - */ - -// http://soledadpenades.com/2007/05/17/arrayindexof-in-internet-explorer/ -if(!Array.prototype.indexOf) { - Array.prototype.indexOf = function(obj){ - for(var i = 0; i < this.length; i++){ - if(this[i] == obj){ - return i; - } - } - return -1; - }; -} - -// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach -if (!Array.prototype.forEach) { - Array.prototype.forEach = function(fn, scope) { - for(var i = 0, len = this.length; i < len; ++i) { - fn.call(scope || this, this[i], i, this); - } - } -} - -// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray -if(!Array.isArray) { - Array.isArray = function (vArg) { - return Object.prototype.toString.call(vArg) === "[object Array]"; - }; -} - -// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/map -// Production steps of ECMA-262, Edition 5, 15.4.4.19 -// Reference: http://es5.github.com/#x15.4.4.19 -if (!Array.prototype.map) { - Array.prototype.map = function(callback, thisArg) { - - var T, A, k; - - if (this == null) { - throw new TypeError(" this is null or not defined"); - } - - // 1. Let O be the result of calling ToObject passing the |this| value as the argument. - var O = Object(this); - - // 2. Let lenValue be the result of calling the Get internal method of O with the argument "length". - // 3. Let len be ToUint32(lenValue). - var len = O.length >>> 0; - - // 4. If IsCallable(callback) is false, throw a TypeError exception. - // See: http://es5.github.com/#x9.11 - if (typeof callback !== "function") { - throw new TypeError(callback + " is not a function"); - } - - // 5. If thisArg was supplied, let T be thisArg; else let T be undefined. - if (thisArg) { - T = thisArg; - } - - // 6. Let A be a new array created as if by the expression new Array(len) where Array is - // the standard built-in constructor with that name and len is the value of len. - A = new Array(len); - - // 7. Let k be 0 - k = 0; - - // 8. Repeat, while k < len - while(k < len) { - - var kValue, mappedValue; - - // a. Let Pk be ToString(k). - // This is implicit for LHS operands of the in operator - // b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk. - // This step can be combined with c - // c. If kPresent is true, then - if (k in O) { - - // i. Let kValue be the result of calling the Get internal method of O with argument Pk. - kValue = O[ k ]; - - // ii. Let mappedValue be the result of calling the Call internal method of callback - // with T as the this value and argument list containing kValue, k, and O. - mappedValue = callback.call(T, kValue, k, O); - - // iii. Call the DefineOwnProperty internal method of A with arguments - // Pk, Property Descriptor {Value: mappedValue, : true, Enumerable: true, Configurable: true}, - // and false. - - // In browsers that support Object.defineProperty, use the following: - // Object.defineProperty(A, Pk, { value: mappedValue, writable: true, enumerable: true, configurable: true }); - - // For best browser support, use the following: - A[ k ] = mappedValue; - } - // d. Increase k by 1. - k++; - } - - // 9. return A - return A; - }; -} - -// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/every -if (!Array.prototype.every) { - Array.prototype.every = function(fun /*, thisp */) { - "use strict"; - - if (this == null) { - throw new TypeError(); - } - - var t = Object(this); - var len = t.length >>> 0; - if (typeof fun != "function") { - throw new TypeError(); - } - - var thisp = arguments[1]; - for (var i = 0; i < len; i++) { - if (i in t && !fun.call(thisp, t[i], i, t)) { - return false; - } - } - - return true; - }; -} - -// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/some -if (!Array.prototype.some) { - Array.prototype.some = function(fun /*, thisp */) { - "use strict"; - - if (this == null) { - throw new TypeError(); - } - - var t = Object(this); - var len = t.length >>> 0; - if (typeof fun != "function") { - throw new TypeError(); - } - - var thisp = arguments[1]; - for (var i = 0; i < len; i++) { - if (i in t && fun.call(thisp, t[i], i, t)) { - return true; - } - } - - return false; - }; -} - -// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind -if (!Function.prototype.bind) { - Function.prototype.bind = function (oThis) { - if (typeof this !== "function") { - // closest thing possible to the ECMAScript 5 internal IsCallable function - throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); - } - - var aArgs = Array.prototype.slice.call(arguments, 1), - fToBind = this, - fNOP = function () {}, - fBound = function () { - return fToBind.apply(this instanceof fNOP && oThis - ? this - : oThis, - aArgs.concat(Array.prototype.slice.call(arguments))); - }; - - fNOP.prototype = this.prototype; - fBound.prototype = new fNOP(); - - return fBound; - }; -} diff --git a/src/type/Complex.js b/src/type/Complex.js deleted file mode 100644 index 28fb03047..000000000 --- a/src/type/Complex.js +++ /dev/null @@ -1,367 +0,0 @@ -var util = require('../util/index.js'), - - number = util.number, - isNumber = util.number.isNumber, - isString = util.string.isString; - -/** - * @constructor Complex - * - * A complex value can be constructed in the following ways: - * var a = new Complex(); - * var b = new Complex(re, im); - * var c = Complex.parse(str); - * - * Example usage: - * var a = new Complex(3, -4); // 3 - 4i - * a.re = 5; // a = 5 - 4i - * var i = a.im; // -4; - * var b = Complex.parse('2 + 6i'); // 2 + 6i - * var c = new Complex(); // 0 + 0i - * var d = math.add(a, b); // 5 + 2i - * - * @param {Number} re The real part of the complex value - * @param {Number} [im] The imaginary part of the complex value - */ -function Complex(re, im) { - if (!(this instanceof Complex)) { - throw new SyntaxError( - 'Complex constructor must be called with the new operator'); - } - - switch (arguments.length) { - case 0: - this.re = 0; - this.im = 0; - break; - - case 2: - if (!isNumber(re) || !isNumber(im)) { - throw new TypeError( - 'Two numbers expected in Complex constructor'); - } - this.re = re; - this.im = im; - break; - - default: - if (arguments.length != 0 && arguments.length != 2) { - throw new SyntaxError( - 'Two or zero arguments expected in Complex constructor'); - } - break; - } -} - -/** - * Test whether value is a Complex value - * @param {*} value - * @return {Boolean} isComplex - */ -Complex.isComplex = function isComplex(value) { - return (value instanceof Complex); -}; - -// private variables and functions for the parser -var text, index, c; - -function skipWhitespace() { - while (c == ' ' || c == '\t') { - next(); - } -} - -function isDigitDot (c) { - return ((c >= '0' && c <= '9') || c == '.'); -} - -function isDigit (c) { - return ((c >= '0' && c <= '9')); -} - -function next() { - index++; - c = text.charAt(index); -} - -function revert(oldIndex) { - index = oldIndex; - c = text.charAt(index); -} - -function parseNumber () { - var number = ''; - var oldIndex; - oldIndex = index; - - if (c == '+') { - next(); - } - else if (c == '-') { - number += c; - next(); - } - - if (!isDigitDot(c)) { - // a + or - must be followed by a digit - revert(oldIndex); - return null; - } - - // get number, can have a single dot - if (c == '.') { - number += c; - next(); - if (!isDigit(c)) { - // this is no legal number, it is just a dot - revert(oldIndex); - return null; - } - } - else { - while (isDigit(c)) { - number += c; - next(); - } - if (c == '.') { - number += c; - next(); - } - } - while (isDigit(c)) { - number += c; - next(); - } - - // check for scientific notation like "2.3e-4" or "1.23e50" - if (c == 'E' || c == 'e') { - number += c; - next(); - - if (c == '+' || c == '-') { - number += c; - next(); - } - - // Scientific notation MUST be followed by an exponent - if (!isDigit(c)) { - // this is no legal number, exponent is missing. - revert(oldIndex); - return null; - } - - while (isDigit(c)) { - number += c; - next(); - } - } - - return number; -} - -function parseComplex () { - // check for 'i', '-i', '+i' - var cnext = text.charAt(index + 1); - if (c == 'I' || c == 'i') { - next(); - return '1'; - } - else if ((c == '+' || c == '-') && (cnext == 'I' || cnext == 'i')) { - var number = (c == '+') ? '1' : '-1'; - next(); - next(); - return number; - } - - return null; -} - -/** - * Create a complex number from a provided real and imaginary number. - * When the imaginary part is zero, a real number is returned instead of - * a complex number. For example: - * Complex.create(2, 3); // returns a Complex(2, 3) - * Complex.create(2, 0); // returns a Number 2 - * - * @param {Number} re - * @param {Number} im - * @return {Complex | Number} value - */ -Complex.create = function create (re, im) { - if (im == 0) { - return re; - } - else { - return new Complex(re, im); - } -}; - -/** - * Parse a complex number from a string. For example Complex.parse("2 + 3i") - * will return a Complex value where re = 2, im = 3. - * Returns null if provided string does not contain a valid complex number. - * @param {String} str - * @returns {Complex | null} complex - */ -Complex.parse = function parse(str) { - text = str; - index = -1; - c = ''; - - if (!isString(text)) { - return null; - } - - next(); - skipWhitespace(); - var first = parseNumber(); - if (first) { - if (c == 'I' || c == 'i') { - // pure imaginary number - next(); - skipWhitespace(); - if (c) { - // garbage at the end. not good. - return null; - } - - return new Complex(0, Number(first)); - } - else { - // complex and real part - skipWhitespace(); - var separator = c; - if (separator != '+' && separator != '-') { - // pure real number - skipWhitespace(); - if (c) { - // garbage at the end. not good. - return null; - } - - return new Complex(Number(first), 0); - } - else { - // complex and real part - next(); - skipWhitespace(); - var second = parseNumber(); - if (second) { - if (c != 'I' && c != 'i') { - // 'i' missing at the end of the complex number - return null; - } - next(); - } - else { - second = parseComplex(); - if (!second) { - // imaginary number missing after separator - return null; - } - } - - if (separator == '-') { - if (second[0] == '-') { - second = '+' + second.substring(1); - } - else { - second = '-' + second; - } - } - - next(); - skipWhitespace(); - if (c) { - // garbage at the end. not good. - return null; - } - - return new Complex(Number(first), Number(second)); - } - } - } - else { - // check for 'i', '-i', '+i' - first = parseComplex(); - if (first) { - skipWhitespace(); - if (c) { - // garbage at the end. not good. - return null; - } - - return new Complex(0, Number(first)); - } - } - - return null; -}; - -/** - * Create a copy of the complex value - * @return {Complex} clone - */ -Complex.prototype.clone = function () { - return new Complex(this.re, this.im); -}; - -/** - * Get string representation of the Complex value - * @return {String} str - */ -Complex.prototype.toString = function () { - var str = ''; - var strRe = number.format(this.re); - var strIm = number.format(this.im); - - if (this.im == 0) { - // real value - str = strRe; - } - else if (this.re == 0) { - // purely complex value - if (this.im == 1) { - str = 'i'; - } - else if (this.im == -1) { - str = '-i'; - } - else { - str = strIm + 'i'; - } - } - else { - // complex value - if (this.im > 0) { - if (this.im == 1) { - str = strRe + ' + i'; - } - else { - str = strRe + ' + ' + strIm + 'i'; - } - } - else { - if (this.im == -1) { - str = strRe + ' - i'; - } - else { - str = strRe + ' - ' + - number.format(Math.abs(this.im)) + 'i'; - } - } - } - - return str; -}; - - -// exports -module.exports = Complex; - -// to trick my IDE which doesn't get it -exports.isComplex = Complex.isComplex; -exports.parse = Complex.parse; -exports.create = Complex.create; - -util.types.addType('complex', Complex); diff --git a/src/type/Help.js b/src/type/Help.js deleted file mode 100644 index 2d41afa33..000000000 --- a/src/type/Help.js +++ /dev/null @@ -1,92 +0,0 @@ -var util = require('../util/index.js'), - object = util.object, - string = util.string; - -/** - * Documentation object - * @param {Object} math The math.js namespace - * @param {Object} doc Object containing properties: - * {String} name - * {String} category - * {String[]} syntax - * {String[]} examples - * {String[]} seealso - * @constructor - */ -function Help (math, doc) { - this.math = math; - this.doc = doc; -} - -/** - * Test whether a value is an instance of Help - * @param {*} value - * @return {Boolean} isHelp - */ -Help.isHelp = function isHelp (value) { - return (value instanceof Help); -}; - -/** - * Generate readable description from a Help object - * @return {String} readableDoc - * @private - */ -Help.prototype.toString = function () { - var doc = this.doc || {}; - var desc = '\n'; - - if (doc.name) { - desc += 'Name: ' + doc.name + '\n\n'; - } - if (doc.category) { - desc += 'Category: ' + doc.category + '\n\n'; - } - if (doc.description) { - desc += 'Description:\n ' + doc.description + '\n\n'; - } - if (doc.syntax) { - desc += 'Syntax:\n ' + doc.syntax.join('\n ') + '\n\n'; - } - if (doc.examples) { - var parser = this.math.parser(); - desc += 'Examples:\n'; - for (var i = 0; i < doc.examples.length; i++) { - var expr = doc.examples[i]; - var res; - try { - res = parser.eval(expr); - } - catch (e) { - res = e; - } - desc += ' ' + expr + '\n'; - if (res && !(res instanceof Help)) { - desc += ' ' + string.format(res) + '\n'; - } - } - desc += '\n'; - } - if (doc.seealso) { - desc += 'See also: ' + doc.seealso.join(', ') + '\n'; - } - - return desc; -}; - -// TODO: implement a toHTML function in Help - -/** - * Export the help object to JSON - */ -Help.prototype.toJSON = function () { - return object.extend({}, this.doc); -}; - -// exports -module.exports = Help; - -// to trick my IDE which doesn't get it -exports.isHelp = Help.isHelp; - -util.types.addType('help', Help); diff --git a/src/type/Matrix.js b/src/type/Matrix.js deleted file mode 100644 index c6b8339ab..000000000 --- a/src/type/Matrix.js +++ /dev/null @@ -1,680 +0,0 @@ -var util = require('../util/index.js'), - Range = require('./Range.js'), - - number = util.number, - string = util.string, - array = util.array, - object = util.object; - -/** - * @constructor Matrix - * - * A Matrix is a wrapper around an Array. A matrix can hold a multi dimensional - * array. A matrix can be constructed as: - * var matrix = new Matrix(data) - * - * Matrix contains the functions to resize, get and set values, get the size, - * clone the matrix and to convert the matrix to a vector, array, or scalar. - * Furthermore, one can iterate over the matrix using map and forEach. - * The internal Array of the Matrix can be accessed using the method valueOf. - * - * Example usage: - * var matrix = new Matrix([[1, 2], [3, 4]); - * matix.size(); // [2, 2] - * matrix.resize([3, 2], 5); - * matrix.valueOf(); // [[1, 2], [3, 4], [5, 5]] - * matrix.get([1,2]) // 3 (indexes are zero-based) - * - * @param {Array | Matrix} [data] A multi dimensional array - */ -function Matrix(data) { - if (!(this instanceof Matrix)) { - throw new SyntaxError( - 'Matrix constructor must be called with the new operator'); - } - - if (data instanceof Matrix || data instanceof Range) { - // clone data from a Matrix or Range - this._data = data.toArray(); - } - else if (Array.isArray(data)) { - // use array as is - this._data = data; - } - else if (data != null) { - // unsupported type - throw new TypeError('Unsupported type of data (' + util.types.type(data) + ')'); - } - else { - // nothing provided - this._data = []; - } - - // verify the size of the array - this._size = array.size(this._data); -} - -/** - * Test whether an object is a Matrix - * @param {*} object - * @return {Boolean} isMatrix - */ -Matrix.isMatrix = function (object) { - return (object instanceof Matrix); -}; - -/** - * Get a value or a submatrix of the matrix. - * @param {Array | Matrix} index Zero-based index - */ -Matrix.prototype.get = function (index) { - var isScalar; - if (index instanceof Matrix) { - // index is scalar when size==[n] or size==[1,1,...] - isScalar = (index.size().length == 1) || !index.size().some(function (i) { - return (i != 0); - }); - index = index.valueOf(); - } - else if (Array.isArray(index)) { - isScalar = !index.some(function (elem) { - var size = array.size(elem.valueOf()); - return (size.length != 0) && (size != [0]); - }); - } - else { - throw new TypeError('Invalid index'); - } - - if (index.length != this._size.length) { - throw new RangeError('Dimension mismatch ' + - '(' + index.length + ' != ' + this._size.length + ')'); - } - - if (isScalar) { - // return a single value - switch (index.length) { - case 1: return _get(this._data, index[0]); - case 2: return _get(_get(this._data, index[0]), index[1]); - default: return _getScalar(this._data, index); - } - } - else { - // return a submatrix - switch (index.length) { - case 1: return new Matrix(_getSubmatrix1D(this._data, index)); - case 2: return new Matrix(_getSubmatrix2D(this._data, index)); - default: return new Matrix(_getSubmatrix(this._data, index, 0)); - } - // TODO: more efficient when creating an empty matrix and setting _data and _size manually - } -}; - -/** - * Get a single value from an array. The method tests whether: - * - index is a non-negative integer - * - index does not exceed the dimensions of array - * @param {Array} arr - * @param {Number} index Zero-based index - * @return {*} value - * @private - */ -function _get (arr, index) { - array.validateIndex(index, arr.length); - return arr[index]; // zero-based index -} - -/** - * Get a single value from the matrix. The value will be a copy of the original - * value in the matrix. - * Index is not checked for correct number of dimensions. - * @param {Array} data - * @param {Number[]} index Zero-based index - * @return {*} scalar - * @private - */ -function _getScalar (data, index) { - index.forEach(function (i) { - data = _get(data, i); - }); - return object.clone(data); -} - -/** - * Get a submatrix of a zero dimensional matrix. - * Index is not checked for correct number of dimensions. - * @param {Array} data - * @param {Array} index Zero-based index - * @return {Array} submatrix - * @private - */ -function _getSubmatrix1D (data, index) { - var current = index[0]; - if (current.map) { - // array or Range - return current.map(function (i) { - return _get(data, i); - }); - } - else { - // scalar - return [ - _get(data, current) - ]; - } -} - -/** - * Get a submatrix of a 2 dimensional matrix. - * Index is not checked for correct number of dimensions. - * @param {Array} data - * @param {Array} index Zero-based index - * @return {Array} submatrix - * @private - */ -function _getSubmatrix2D (data, index) { - var rows = index[0]; - var cols = index[1]; - - if (rows.map) { - if (cols.map) { - return rows.map(function (row) { - var child = _get(data, row); - return cols.map(function (col) { - return _get(child, col); - }); - }); - } - else { - return rows.map(function (row) { - return [ - _get(_get(data, row), cols) - ]; - }); - } - } - else { - if (cols.map) { - var child = _get(data, rows); - return [ - cols.map(function (col) { - return _get(child, col); - }) - ] - } - else { - return [ - [ - _get(_get(data, rows), cols) - ] - ]; - } - } -} - -/** - * Get a submatrix of a multi dimensional matrix. - * Index is not checked for correct number of dimensions. - * @param {Array} data - * @param {Array} index Zero-based index - * @param {number} dim - * @return {Array} submatrix - * @private - */ -function _getSubmatrix (data, index, dim) { - var last = (dim == index.length - 1); - var current = index[dim]; - var recurse = function (i) { - var child = _get(data, i); - return last ? child : _getSubmatrix(child, index, dim + 1); - }; - - if (current.map) { - // array or Range - return current.map(recurse); - } - else { - // scalar - return [ - recurse(current) - ]; - } -} - -/** - * Replace a value or a submatrix in the matrix. - * Indexes are zero-based. - * @param {Array | Matrix} index zero-based index - * @param {*} submatrix - * @return {Matrix} itself - */ -Matrix.prototype.set = function (index, submatrix) { - var isScalar; - if (index instanceof Matrix) { - // index is scalar when size==[n] or size==[0,0,...] - isScalar = (index.size().length == 1) || !index.size().some(function (i) { - return (i != 0); - }); - index = index.valueOf(); - } - else if (Array.isArray(index)) { - isScalar = !index.some(function (elem) { - var size = array.size(elem.valueOf()); - return (size.length != 0) && (size != [0]); - }); - } - else { - throw new TypeError('Invalid index'); - } - - if (submatrix instanceof Matrix || submatrix instanceof Range) { - submatrix = submatrix.valueOf(); - } - - if (index.length < this._size.length) { - throw new RangeError('Dimension mismatch ' + - '(' + index.length + ' != ' + this._size.length + ')'); - } - - if (isScalar) { - // set a scalar - // check whether submatrix is no matrix/array - if (array.size(submatrix.valueOf()).length != 0) { - throw new TypeError('Scalar value expected'); - } - - switch (index.length) { - case 1: _setScalar1D(this._data, this._size, index, submatrix); break; - case 2: _setScalar2D(this._data, this._size, index, submatrix); break; - default: _setScalar(this._data, this._size, index, submatrix); break; - } - } - else { - // set a submatrix - var subsize = this._size.concat(); - _setSubmatrix (this._data, subsize, index, 0, submatrix); - if (!object.deepEqual(this._size, subsize)) { - _init(this._data); - this.resize(subsize); - } - } - - return this; -}; - -/** - * Replace a single value in an array. The method tests whether index is a - * non-negative integer - * @param {Array} arr - * @param {Number} index Zero-based index - * @param {*} value - * @private - */ -function _set (arr, index, value) { - array.validateIndex(index); - if (Array.isArray(value)) { - throw new TypeError('Dimension mismatch, value expected instead of array'); - } - arr[index] = value; // zero-based index -} - -/** - * Replace a single value in a multi dimensional matrix - * @param {Array} data - * @param {Number[]} size - * @param {Number[]} index Zero-based index - * @param {*} value - * @private - */ -function _setScalar (data, size, index, value) { - var resized = false; - if (index.length > size.length) { - // dimension added - resized = true; - } - - for (var i = 0; i < index.length; i++) { - var index_i = index[i]; - array.validateIndex(index_i); - if ((size[i] == null) || (index_i + 1 > size[i])) { - size[i] = index_i + 1; // size is index + 1 as index is zero-based - resized = true; - } - } - - if (resized) { - array.resize(data, size, 0); - } - - var len = size.length; - index.forEach(function (v, i) { - if (i < len - 1) { - data = data[v]; // zero-based index - } - else { - data[v] = value; // zero-based index - } - }); -} - -/** - * Replace a single value in a zero dimensional matrix - * @param {Array} data - * @param {Number[]} size - * @param {Number[]} index zero-based index - * @param {*} value - * @private - */ -function _setScalar1D (data, size, index, value) { - var row = index[0]; - array.validateIndex(row); - if (row + 1 > size[0]) { - array.resize(data, [row + 1], 0); // size is index + 1 as index is zero-based - size[0] = row + 1; - } - data[row] = value; // zero-based index -} - -/** - * Replace a single value in a two dimensional matrix - * @param {Array} data - * @param {Number[]} size - * @param {Number[]} index zero-based index - * @param {*} value - * @private - */ -function _setScalar2D (data, size, index, value) { - var row = index[0]; - var col = index[1]; - array.validateIndex(row); - array.validateIndex(col); - - var resized = false; - if (row + 1 > (size[0] || 0)) { - size[0] = row + 1; // size is index + 1 as index is zero-based - resized = true; - } - if (col + 1 > (size[1] || 0)) { - size[1] = col + 1; // size is index + 1 as index is zero-based - resized = true; - } - if (resized) { - array.resize(data, size, 0); - } - - data[row][col] = value; // zero-based index -} - -/** - * Replace a submatrix of a multi dimensional matrix. - * @param {Array} data - * @param {Array} size - * @param {Array} index zero-based index - * @param {number} dim - * @param {Array} submatrix - * @private - */ -function _setSubmatrix (data, size, index, dim, submatrix) { - var last = (dim == index.length - 1); - var current = index[dim]; - var recurse = function (dataIndex, subIndex) { - if (last) { - _set(data, dataIndex, submatrix[subIndex]); - if (dataIndex + 1 > (size[dim] || 0)) { - size[dim] = dataIndex + 1; - } - } - else { - var child = data[dataIndex]; // zero-based index - if (!Array.isArray(child)) { - data[dataIndex] = child = [child]; // zero-based index - } - if (dataIndex + 1 > (size[dim] || 0)) { - size[dim] = dataIndex + 1; - } - _setSubmatrix(child, size, index, dim + 1, submatrix[subIndex]); - } - }; - - if (current.map) { - // array or Range - var len = (current.size && current.size() || current.length); - if (len != submatrix.length) { - throw new RangeError('Dimensions mismatch ' + - '(' + len + ' != '+ submatrix.length + ')'); - } - current.map(recurse); - } - else { - // scalar - recurse(current, 0) - } -} - -/** - * Recursively initialize all undefined values in the array with zeros - * @param array - * @private - */ -function _init(array) { - for (var i = 0, len = array.length; i < len; i++) { - var value = array[i]; - if (Array.isArray(value)) { - _init(value); - } - else if (value == undefined) { - array[i] = 0; - } - } -} - -/** - * Resize the matrix - * @param {Number[]} size - * @param {*} [defaultValue] Default value, filled in on new entries. - * If not provided, the matrix will be filled - * with zeros. - */ -Matrix.prototype.resize = function (size, defaultValue) { - array.resize(this._data, size, defaultValue); - this._size = object.clone(size); -}; - -/** - * Create a clone of the matrix - * @return {Matrix} clone - */ -Matrix.prototype.clone = function () { - var matrix = new Matrix(); - matrix._data = object.clone(this._data); - matrix._size = object.clone(this._size); - return matrix; -}; - -/** - * Retrieve the size of the matrix. - * The size of the matrix will be validated too - * @returns {Number[]} size - */ -Matrix.prototype.size = function () { - return this._size; -}; - -/** - * Create a new matrix with the results of the callback function executed on - * each entry of the matrix. - * @param {function} callback The callback method is invoked with three - * parameters: the value of the element, the index - * of the element, and the Matrix being traversed. - * @return {Matrix} matrix - */ -Matrix.prototype.map = function (callback) { - var me = this; - var matrix = new Matrix(); - var index = []; - var recurse = function (value, dim) { - if (Array.isArray(value)) { - return value.map(function (child, i) { - index[dim] = i; // zero-based index - return recurse(child, dim + 1); - }); - } - else { - return callback(value, index, me); - } - }; - matrix._data = recurse(this._data, 0); - matrix._size = object.clone(this._size); - - return matrix; -}; - -/** - * Execute a callback method on each entry of the matrix. - * @param {function} callback The callback method is invoked with three - * parameters: the value of the element, the index - * of the element, and the Matrix being traversed. - */ -Matrix.prototype.forEach = function (callback) { - var me = this; - var index = []; - var recurse = function (value, dim) { - if (Array.isArray(value)) { - value.forEach(function (child, i) { - index[dim] = i; // zero-based index - recurse(child, dim + 1); - }); - } - else { - callback(value, index, me); - } - }; - recurse(this._data, 0); -}; - -/** - * Create a scalar with a copy of the data of the Matrix - * Will return null if the matrix does not consist of a scalar value - * @return {* | null} scalar - */ -Matrix.prototype.toScalar = function () { - var scalar = this._data; - while (Array.isArray(scalar) && scalar.length == 1) { - scalar = scalar[0]; - } - - if (Array.isArray(scalar)) { - return null; - } - else { - return object.clone(scalar); - } -}; - -/** - * Test whether the matrix is a scalar. - * @return {boolean} isScalar - */ -Matrix.prototype.isScalar = function () { - return this._size.every(function (s) { - return (s <= 1); - }); -}; - -/** - * Create a vector with a copy of the data of the Matrix - * Returns null if the Matrix does not contain a vector - * - * A matrix is a vector when it has 0 or 1 dimensions, or has multiple - * dimensions where maximum one of the dimensions has a size larger than 1. - * return {Array | null} vector - */ -Matrix.prototype.toVector = function () { - var count = 0; - var dim = undefined; - var index = []; - this._size.forEach(function (length, i) { - if (length > 1) { - count++; - dim = i; - } - index[i] = 0; - }); - - if (count == 0) { - // scalar or empty - var scalar = this.toScalar(); - if (scalar) { - return [scalar]; - } - else { - return []; - } - } - else if (count == 1) { - // valid vector - var vector = []; - var recurse = function (data) { - if (Array.isArray(data)) { - data.forEach(recurse); - } - else { - vector.push(data); - } - }; - recurse(this._data); - return vector; - } - else { - // count > 1, this is no vector - return null; - } -}; - -/** - * Test if the matrix contains a vector. - * A matrix is a vector when it has 0 or 1 dimensions, or has multiple - * dimensions where maximum one of the dimensions has a size larger than 1. - * return {boolean} isVector - */ -Matrix.prototype.isVector = function () { - var count = 0; - this._size.forEach(function (length) { - if (length > 1) { - count++; - } - }); - return (count <= 1); -}; - -/** - * Create an Array with a copy of the data of the Matrix - * @returns {Array} array - */ -Matrix.prototype.toArray = function () { - return object.clone(this._data); -}; - -/** - * Get the primitive value of the Matrix: a multidimensional array - * @returns {Array} array - */ -Matrix.prototype.valueOf = function () { - return this._data; -}; - -/** - * Get a string representation of the matrix - * @returns {String} str - */ -Matrix.prototype.toString = function () { - return string.format(this._data); -}; - -// exports -module.exports = Matrix; - -// to trick my IDE which doesn't get it -exports.isMatrix = Matrix.isMatrix; - -util.types.addType('matrix', Matrix); diff --git a/src/type/Range.js b/src/type/Range.js deleted file mode 100644 index 46c8329b5..000000000 --- a/src/type/Range.js +++ /dev/null @@ -1,255 +0,0 @@ -var util = require('../util/index.js'), - - number = util.number, - string = util.string, - array = util.array; - -/** - * @constructor Range - * Create a range. A range works similar to an Array, with functions like - * forEach and map. However, a Range object is very cheap to create compared to - * a large Array with indexes, as it stores only a start, step and end value of - * the range. - * - * A range can be constructed as: - * var range = new Range(start, end); - * var range = new Range(start, end, step); - * - * To get the result of the range: - * range.forEach(function (x) { - * console.log(x); - * }); - * range.map(function (x) { - * return math.sin(x); - * }); - * range.toArray(); - * - * Example usage: - * var c = new Range(2, 6); // 2:1:5 - * c.toArray(); // [2, 3, 4, 5] - * var d = new Range(2, -3, -1); // 2:-1:-2 - * d.toArray(); // [2, 1, 0, -1, -2] - * - * @param {Number} start included lower bound - * @param {Number} end excluded upper bound - * @param {Number} [step] step size, default value is 1 - */ -function Range(start, end, step) { - if (!(this instanceof Range)) { - throw new SyntaxError( - 'Range constructor must be called with the new operator'); - } - - if (start != null && !number.isNumber(start)) { - throw new TypeError('Parameter start must be a number'); - } - if (end != null && !number.isNumber(end)) { - throw new TypeError('Parameter end must be a number'); - } - if (step != null && !number.isNumber(step)) { - throw new TypeError('Parameter step must be a number'); - } - - this.start = (start != null) ? start : 0; - this.end = (end != null) ? end : 0; - this.step = (step != null) ? step : 1; -} - -/** - * Parse a string into a range, - * The string contains the start, optional step, and end, separated by a colon. - * If the string does not contain a valid range, null is returned. - * For example str='0:2:11'. - * @param {String} str - * @return {Range | null} range - */ -Range.parse = function parse (str) { - if (!string.isString(str)) { - return null; - } - - var args = str.split(':'); - var nums = args.map(function (arg) { - return Number(arg); - }); - - var invalid = nums.some(function (num) { - return isNaN(num); - }); - if(invalid) { - return null; - } - - switch (nums.length) { - case 2: return new Range(nums[0], nums[1]); - case 3: return new Range(nums[0], nums[2], nums[1]); - default: return null; - } -}; - -/** - * Create a clone of the range - * @return {Range} clone - */ -Range.prototype.clone = function () { - return new Range(this.start, this.end, this.step); -}; - -/** - * Test whether an object is a Range - * @param {*} object - * @return {Boolean} isRange - */ -Range.isRange = function isRange(object) { - return (object instanceof Range); -}; - -/** - * Retrieve the size of the range. - * @returns {Number[]} size - */ -Range.prototype.size = function () { - var len = 0, - start = Number(this.start), - step = Number(this.step), - end = Number(this.end), - diff = end - start; - - if (number.sign(step) == number.sign(diff)) { - len = Math.floor((diff) / step); - } - else if (diff == 0) { - len = 0; - } - - if (isNaN(len)) { - len = 0; - } - return [len]; -}; - -/** - * Execute a callback function for each value in the range. - * @param {function} callback The callback method is invoked with three - * parameters: the value of the element, the index - * of the element, and the Matrix being traversed. - */ -Range.prototype.forEach = function (callback) { - var x = Number(this.start); - var step = Number(this.step); - var end = Number(this.end); - var i = 0; - - if (step > 0) { - while (x < end) { - callback(x, i, this); - x += step; - i++; - } - } - else if (step < 0) { - while (x > end) { - callback(x, i, this); - x += step; - i++; - } - } -}; - -/** - * Execute a callback function for each value in the Range, and return the - * results as an array - * @param {function} callback The callback method is invoked with three - * parameters: the value of the element, the index - * of the element, and the Matrix being traversed. - * @returns {Array} array - */ -Range.prototype.map = function (callback) { - var array = []; - this.forEach(function (value, index, obj) { - array[index] = callback(value, index, obj); - }); - return array; -}; - -/** - * Create an Array with a copy of the Ranges data - * @returns {Array} array - */ -Range.prototype.toArray = function () { - var array = []; - this.forEach(function (value, index) { - array[index] = value; - }); - return array; -}; - -/** - * Create an array with a copy of the Ranges data. - * This method is equal to Range.toArray. - * @return {Array} vector - */ -Range.prototype.toVector = Range.prototype.toArray; - -/** - * Test if the range contains a vector. For a range, this is always the case - * return {boolean} isVector - */ -Range.prototype.isVector = function () { - return true; -}; - -/** - * Create a scalar with a copy of the data of the Range - * Will return null if the range does not consist of a scalar value - * @return {* | null} scalar - */ -Range.prototype.toScalar = function () { - var array = this.toArray(); - if (array.length == 1) { - return array[0]; - } - else { - return null; - } -}; - -/** - * Test whether the matrix is a scalar. - * @return {boolean} isScalar - */ -Range.prototype.isScalar = function () { - return (this.size()[0] == 1); -}; - -/** - * Get the primitive value of the Range, a one dimensional array - * @returns {Array} array - */ -Range.prototype.valueOf = function () { - // TODO: implement a caching mechanism for range.valueOf() - return this.toArray(); -}; - -/** - * Get the string representation of the range, for example '2:6' or '0:0.2:11' - * @returns {String} str - */ -Range.prototype.toString = function () { - var str = number.format(Number(this.start)); - if (this.step != 1) { - str += ':' + number.format(Number(this.step)); - } - str += ':' + number.format(Number(this.end)); - return str; -}; - - -// exports -module.exports = Range; - -// to trick my IDE which doesn't get it -exports.isRange = Range.isRange; -exports.parse = Range.parse; - -util.types.addType('range', Range); diff --git a/src/type/Unit.js b/src/type/Unit.js deleted file mode 100644 index 5e4b9b6f2..000000000 --- a/src/type/Unit.js +++ /dev/null @@ -1,725 +0,0 @@ -var util = require('../util/index.js'), - - number = util.number, - string = util.string, - isNumber = util.number.isNumber, - isString = util.string.isString; - -/** - * @constructor Unit - * - * A unit can be constructed in the following ways: - * var a = new Unit(value, unit); - * var b = new Unit(null, unit); - * var c = Unit.parse(str); - * - * Example usage: - * var a = new Unit(5, 'cm'); // 50 mm - * var b = Unit.parse('23 kg'); // 23 kg - * var c = math.in(a, new Unit(null, 'm'); // 0.05 m - * - * @param {Number} [value] A value like 5.2 - * @param {String} [unit] A unit like "cm" or "inch" - */ -function Unit(value, unit) { - if (!(this instanceof Unit)) { - throw new Error('Unit constructor must be called with the new operator'); - } - - if (value != null && !isNumber(value)) { - throw new TypeError('First parameter in Unit constructor must be a number'); - } - if (unit != null && !isString(unit)) { - throw new TypeError('Second parameter in Unit constructor must be a string'); - } - - if (unit != null) { - // find the unit and prefix from the string - var res = _findUnit(unit); - if (!res) { - throw new SyntaxError('String "' + unit + '" is no unit'); - } - this.unit = res.unit; - this.prefix = res.prefix; - } - else { - this.unit = UNIT_NONE; - this.prefix = PREFIX_NONE; // link to a list with supported prefixes - } - - if (value != null) { - this.value = this._normalize(value); - this.fixPrefix = false; // is set true by the methods Unit.in and math.in - } - else { - this.value = null; - this.fixPrefix = true; - } -} - -// private variables and functions for the Unit parser -var text, index, c; - -function skipWhitespace() { - while (c == ' ' || c == '\t') { - next(); - } -} - -function isDigitDot (c) { - return ((c >= '0' && c <= '9') || c == '.'); -} - -function isDigit (c) { - return ((c >= '0' && c <= '9')); -} - -function next() { - index++; - c = text.charAt(index); -} - -function revert(oldIndex) { - index = oldIndex; - c = text.charAt(index); -} - -function parseNumber () { - var number = ''; - var oldIndex; - oldIndex = index; - - if (c == '+') { - next(); - } - else if (c == '-') { - number += c; - next(); - } - - if (!isDigitDot(c)) { - // a + or - must be followed by a digit - revert(oldIndex); - return null; - } - - // get number, can have a single dot - if (c == '.') { - number += c; - next(); - if (!isDigit(c)) { - // this is no legal number, it is just a dot - revert(oldIndex); - return null; - } - } - else { - while (isDigit(c)) { - number += c; - next(); - } - if (c == '.') { - number += c; - next(); - } - } - while (isDigit(c)) { - number += c; - next(); - } - - // check for scientific notation like "2.3e-4" or "1.23e50" - if (c == 'E' || c == 'e') { - number += c; - next(); - - if (c == '+' || c == '-') { - number += c; - next(); - } - - // Scientific notation MUST be followed by an exponent - if (!isDigit(c)) { - // this is no legal number, exponent is missing. - revert(oldIndex); - return null; - } - - while (isDigit(c)) { - number += c; - next(); - } - } - - return number; -} - -function parseUnit() { - var unit = ''; - - skipWhitespace(); - while (c && c != ' ' && c != '\t') { - unit += c; - next(); - } - - return unit || null; -} - -/** - * Parse a string into a unit. Returns null if the provided string does not - * contain a valid unit. - * @param {String} str A string like "5.2 inch", "4e2 kg" - * @return {Unit | null} unit - */ -Unit.parse = function parse(str) { - text = str; - index = -1; - c = ''; - - if (!isString(text)) { - return null; - } - - next(); - skipWhitespace(); - var value = parseNumber(); - var unit; - if (value) { - unit = parseUnit(); - - next(); - skipWhitespace(); - if (c) { - // garbage at the end. not good. - return null; - } - - if (value && unit) { - return new Unit(Number(value), unit); - } - } - else { - unit = parseUnit(); - - next(); - skipWhitespace(); - if (c) { - // garbage at the end. not good. - return null; - } - - return new Unit(null, unit) - } - - return null; -}; - -/** - * Test whether value is of type Unit - * @param {*} value - * @return {Boolean} isUnit - */ -Unit.isUnit = function isUnit(value) { - return (value instanceof Unit); -}; - -/** - * create a copy of this unit - * @return {Unit} clone - */ -Unit.prototype.clone = function () { - var clone = new Unit(); - - for (var p in this) { - if (this.hasOwnProperty(p)) { - clone[p] = this[p]; - } - } - - return clone; -}; - -/** - * Normalize a value, based on its currently set unit - * @param {Number} value - * @return {Number} normalized value - * @private - */ -Unit.prototype._normalize = function(value) { - return (value + this.unit.offset) * - this.unit.value * this.prefix.value; -}; - -/** - * Unnormalize a value, based on its currently set unit - * @param {Number} value - * @param {Number} [prefixValue] Optional prefix value to be used - * @return {Number} unnormalized value - * @private - */ -Unit.prototype._unnormalize = function (value, prefixValue) { - if (prefixValue == undefined) { - return value / this.unit.value / this.prefix.value - - this.unit.offset; - } - else { - return value / this.unit.value / prefixValue - - this.unit.offset; - } -}; - -/** - * Find a unit from a string - * @param {String} str A string like 'cm' or 'inch' - * @returns {Object | null} result When found, an object with fields unit and - * prefix is returned. Else, null is returned. - * @private - */ -function _findUnit(str) { - for (var i = 0, iMax = UNITS.length; i < iMax; i++) { - var UNIT = UNITS[i]; - - if (string.endsWith(str, UNIT.name) ) { - var prefixLen = (str.length - UNIT.name.length); - var prefixName = str.substring(0, prefixLen); - var prefix = UNIT.prefixes[prefixName]; - if (prefix !== undefined) { - // store unit, prefix, and value - return { - unit: UNIT, - prefix: prefix - }; - } - } - } - - return null; -} - -/** - * Test if the given expression is a unit. - * The unit can have a prefix but cannot have a value. - * @param {String} unit A plain unit without value. Can have prefix, like "cm" - * @return {Boolean} true if the given string is a unit - */ -Unit.isPlainUnit = function (unit) { - return (_findUnit(unit) != null); -}; - -/** - * check if this unit has given base unit - * @param {BASE_UNITS | undefined} base - */ -Unit.prototype.hasBase = function(base) { - if (this.unit.base === undefined) { - return (base === undefined); - } - return (this.unit.base === base); -}; - -/** - * Check if this unit has a base equal to another base - * @param {Unit} other - * @return {Boolean} true if equal base - */ -Unit.prototype.equalBase = function(other) { - return (this.unit.base === other.unit.base); -}; - -/** - * Check if this unit equals another unit - * @param {Unit} other - * @return {Boolean} true if both units are equal - */ -Unit.prototype.equals = function(other) { - return (this.equalBase(other) && this.value == other.value); -}; - -/** - * Create a clone of this unit with a representation - * @param {String | Unit} plainUnit A plain unit, without value. Can have prefix, like "cm" - * @returns {Unit} unit having fixed, specified unit - */ -Unit.prototype['in'] = function (plainUnit) { - var other; - if (isString(plainUnit)) { - other = new Unit(null, plainUnit); - - if (!this.equalBase(other)) { - throw new Error('Units do not match'); - } - - other.value = this.value; - return other; - } - else if (plainUnit instanceof Unit) { - if (!this.equalBase(plainUnit)) { - throw new Error('Units do not match'); - } - if (plainUnit.value != null) { - throw new Error('Cannot convert to a unit with a value'); - } - if (plainUnit.unit == null) { - throw new Error('Unit expected on the right hand side of function in'); - } - - other = plainUnit.clone(); - other.value = this.value; - other.fixPrefix = true; - return other; - } - else { - throw new Error('String or Unit expected as parameter'); - } -}; - -/** - * Return the value of the unit when represented with given plain unit - * @param {String | Unit} plainUnit For example 'cm' or 'inch' - * @return {Number} value - */ -Unit.prototype.toNumber = function (plainUnit) { - var other = this['in'](plainUnit); - var prefix = this.fixPrefix ? other._bestPrefix() : other.prefix; - return other._unnormalize(other.value, prefix.value); -}; - -/** - * Get string representation - * @return {String} - */ -Unit.prototype.toString = function() { - var value, str; - if (!this.fixPrefix) { - var bestPrefix = this._bestPrefix(); - value = this._unnormalize(this.value, bestPrefix.value); - str = (this.value != null) ? number.format(value) + ' ' : ''; - str += bestPrefix.name + this.unit.name; - } - else { - value = this._unnormalize(this.value); - str = (this.value != null) ? number.format(value) + ' ' : ''; - str += this.prefix.name + this.unit.name; - } - return str; -}; - -/** - * Calculate the best prefix using current value. - * @returns {Object} prefix - * @private - */ -Unit.prototype._bestPrefix = function () { - // find the best prefix value (resulting in the value of which - // the absolute value of the log10 is closest to zero, - // though with a little offset of 1.2 for nicer values: you get a - // sequence 1mm 100mm 500mm 0.6m 1m 10m 100m 500m 0.6km 1km ... - var absValue = Math.abs(this.value / this.unit.value); - var bestPrefix = PREFIX_NONE; - var bestDiff = Math.abs( - Math.log(absValue / bestPrefix.value) / Math.LN10 - 1.2); - - var prefixes = this.unit.prefixes; - for (var p in prefixes) { - if (prefixes.hasOwnProperty(p)) { - var prefix = prefixes[p]; - if (prefix.scientific) { - var diff = Math.abs( - Math.log(absValue / prefix.value) / Math.LN10 - 1.2); - - if (diff < bestDiff) { - bestPrefix = prefix; - bestDiff = diff; - } - } - } - } - - return bestPrefix; -}; - -var PREFIXES = { - 'NONE': { - '': {'name': '', 'value': 1, 'scientific': true} - }, - 'SHORT': { - '': {'name': '', 'value': 1, 'scientific': true}, - - 'da': {'name': 'da', 'value': 1e1, 'scientific': false}, - 'h': {'name': 'h', 'value': 1e2, 'scientific': false}, - 'k': {'name': 'k', 'value': 1e3, 'scientific': true}, - 'M': {'name': 'M', 'value': 1e6, 'scientific': true}, - 'G': {'name': 'G', 'value': 1e9, 'scientific': true}, - 'T': {'name': 'T', 'value': 1e12, 'scientific': true}, - 'P': {'name': 'P', 'value': 1e15, 'scientific': true}, - 'E': {'name': 'E', 'value': 1e18, 'scientific': true}, - 'Z': {'name': 'Z', 'value': 1e21, 'scientific': true}, - 'Y': {'name': 'Y', 'value': 1e24, 'scientific': true}, - - 'd': {'name': 'd', 'value': 1e-1, 'scientific': false}, - 'c': {'name': 'c', 'value': 1e-2, 'scientific': false}, - 'm': {'name': 'm', 'value': 1e-3, 'scientific': true}, - // 'µ': {'name': 'µ', 'value': 1e-6, 'scientific': true}, - 'u': {'name': 'u', 'value': 1e-6, 'scientific': true}, - 'n': {'name': 'n', 'value': 1e-9, 'scientific': true}, - 'p': {'name': 'p', 'value': 1e-12, 'scientific': true}, - 'f': {'name': 'f', 'value': 1e-15, 'scientific': true}, - 'a': {'name': 'a', 'value': 1e-18, 'scientific': true}, - 'z': {'name': 'z', 'value': 1e-21, 'scientific': true}, - 'y': {'name': 'y', 'value': 1e-24, 'scientific': true} - }, - 'LONG': { - '': {'name': '', 'value': 1, 'scientific': true}, - - 'deca': {'name': 'deca', 'value': 1e1, 'scientific': false}, - 'hecto': {'name': 'hecto', 'value': 1e2, 'scientific': false}, - 'kilo': {'name': 'kilo', 'value': 1e3, 'scientific': true}, - 'mega': {'name': 'mega', 'value': 1e6, 'scientific': true}, - 'giga': {'name': 'giga', 'value': 1e9, 'scientific': true}, - 'tera': {'name': 'tera', 'value': 1e12, 'scientific': true}, - 'peta': {'name': 'peta', 'value': 1e15, 'scientific': true}, - 'exa': {'name': 'exa', 'value': 1e18, 'scientific': true}, - 'zetta': {'name': 'zetta', 'value': 1e21, 'scientific': true}, - 'yotta': {'name': 'yotta', 'value': 1e24, 'scientific': true}, - - 'deci': {'name': 'deci', 'value': 1e-1, 'scientific': false}, - 'centi': {'name': 'centi', 'value': 1e-2, 'scientific': false}, - 'milli': {'name': 'milli', 'value': 1e-3, 'scientific': true}, - 'micro': {'name': 'micro', 'value': 1e-6, 'scientific': true}, - 'nano': {'name': 'nano', 'value': 1e-9, 'scientific': true}, - 'pico': {'name': 'pico', 'value': 1e-12, 'scientific': true}, - 'femto': {'name': 'femto', 'value': 1e-15, 'scientific': true}, - 'atto': {'name': 'atto', 'value': 1e-18, 'scientific': true}, - 'zepto': {'name': 'zepto', 'value': 1e-21, 'scientific': true}, - 'yocto': {'name': 'yocto', 'value': 1e-24, 'scientific': true} - }, - 'BINARY_SHORT': { - '': {'name': '', 'value': 1, 'scientific': true}, - 'k': {'name': 'k', 'value': 1024, 'scientific': true}, - 'M': {'name': 'M', 'value': Math.pow(1024, 2), 'scientific': true}, - 'G': {'name': 'G', 'value': Math.pow(1024, 3), 'scientific': true}, - 'T': {'name': 'T', 'value': Math.pow(1024, 4), 'scientific': true}, - 'P': {'name': 'P', 'value': Math.pow(1024, 5), 'scientific': true}, - 'E': {'name': 'E', 'value': Math.pow(1024, 6), 'scientific': true}, - 'Z': {'name': 'Z', 'value': Math.pow(1024, 7), 'scientific': true}, - 'Y': {'name': 'Y', 'value': Math.pow(1024, 8), 'scientific': true}, - - 'Ki': {'name': 'Ki', 'value': 1024, 'scientific': true}, - 'Mi': {'name': 'Mi', 'value': Math.pow(1024, 2), 'scientific': true}, - 'Gi': {'name': 'Gi', 'value': Math.pow(1024, 3), 'scientific': true}, - 'Ti': {'name': 'Ti', 'value': Math.pow(1024, 4), 'scientific': true}, - 'Pi': {'name': 'Pi', 'value': Math.pow(1024, 5), 'scientific': true}, - 'Ei': {'name': 'Ei', 'value': Math.pow(1024, 6), 'scientific': true}, - 'Zi': {'name': 'Zi', 'value': Math.pow(1024, 7), 'scientific': true}, - 'Yi': {'name': 'Yi', 'value': Math.pow(1024, 8), 'scientific': true} - }, - 'BINARY_LONG': { - '': {'name': '', 'value': 1, 'scientific': true}, - 'kilo': {'name': 'kilo', 'value': 1024, 'scientific': true}, - 'mega': {'name': 'mega', 'value': Math.pow(1024, 2), 'scientific': true}, - 'giga': {'name': 'giga', 'value': Math.pow(1024, 3), 'scientific': true}, - 'tera': {'name': 'tera', 'value': Math.pow(1024, 4), 'scientific': true}, - 'peta': {'name': 'peta', 'value': Math.pow(1024, 5), 'scientific': true}, - 'exa': {'name': 'exa', 'value': Math.pow(1024, 6), 'scientific': true}, - 'zetta': {'name': 'zetta', 'value': Math.pow(1024, 7), 'scientific': true}, - 'yotta': {'name': 'yotta', 'value': Math.pow(1024, 8), 'scientific': true}, - - 'kibi': {'name': 'kibi', 'value': 1024, 'scientific': true}, - 'mebi': {'name': 'mebi', 'value': Math.pow(1024, 2), 'scientific': true}, - 'gibi': {'name': 'gibi', 'value': Math.pow(1024, 3), 'scientific': true}, - 'tebi': {'name': 'tebi', 'value': Math.pow(1024, 4), 'scientific': true}, - 'pebi': {'name': 'pebi', 'value': Math.pow(1024, 5), 'scientific': true}, - 'exi': {'name': 'exi', 'value': Math.pow(1024, 6), 'scientific': true}, - 'zebi': {'name': 'zebi', 'value': Math.pow(1024, 7), 'scientific': true}, - 'yobi': {'name': 'yobi', 'value': Math.pow(1024, 8), 'scientific': true} - } -}; - -var PREFIX_NONE = {'name': '', 'value': 1, 'scientific': true}; - -var BASE_UNITS = { - 'NONE': {}, - - 'LENGTH': {}, // meter - 'MASS': {}, // kilogram - 'TIME': {}, // second - 'CURRENT': {}, // ampere - 'TEMPERATURE': {}, // kelvin - 'LUMINOUS_INTENSITY': {}, // candela - 'AMOUNT_OF_SUBSTANCE': {}, // mole - - 'FORCE': {}, // Newton - 'SURFACE': {}, // m2 - 'VOLUME': {}, // m3 - 'ANGLE': {}, // rad - 'BIT': {} // bit (digital) -}; - -BASE_UNIT_NONE = {}; - -UNIT_NONE = {'name': '', 'base': BASE_UNIT_NONE, 'value': 1, 'offset': 0}; - -var UNITS = [ - // length - {'name': 'meter', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.LONG, 'value': 1, 'offset': 0}, - {'name': 'inch', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.0254, 'offset': 0}, - {'name': 'foot', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.3048, 'offset': 0}, - {'name': 'yard', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.9144, 'offset': 0}, - {'name': 'mile', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 1609.344, 'offset': 0}, - {'name': 'link', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.201168, 'offset': 0}, - {'name': 'rod', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 5.029210, 'offset': 0}, - {'name': 'chain', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 20.1168, 'offset': 0}, - {'name': 'angstrom', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 1e-10, 'offset': 0}, - - {'name': 'm', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.SHORT, 'value': 1, 'offset': 0}, - //{'name': 'in', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.0254, 'offset': 0}, not supported, In is an operator - {'name': 'ft', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.3048, 'offset': 0}, - {'name': 'yd', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.9144, 'offset': 0}, - {'name': 'mi', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 1609.344, 'offset': 0}, - {'name': 'li', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.201168, 'offset': 0}, - {'name': 'rd', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 5.029210, 'offset': 0}, - {'name': 'ch', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 20.1168, 'offset': 0}, - {'name': 'mil', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.0000254, 'offset': 0}, // 1/1000 inch - - // Surface - {'name': 'm2', 'base': BASE_UNITS.SURFACE, 'prefixes': PREFIXES.SHORT, 'value': 1, 'offset': 0}, - {'name': 'sqin', 'base': BASE_UNITS.SURFACE, 'prefixes': PREFIXES.NONE, 'value': 0.00064516, 'offset': 0}, // 645.16 mm2 - {'name': 'sqft', 'base': BASE_UNITS.SURFACE, 'prefixes': PREFIXES.NONE, 'value': 0.09290304, 'offset': 0}, // 0.09290304 m2 - {'name': 'sqyd', 'base': BASE_UNITS.SURFACE, 'prefixes': PREFIXES.NONE, 'value': 0.83612736, 'offset': 0}, // 0.83612736 m2 - {'name': 'sqmi', 'base': BASE_UNITS.SURFACE, 'prefixes': PREFIXES.NONE, 'value': 2589988.110336, 'offset': 0}, // 2.589988110336 km2 - {'name': 'sqrd', 'base': BASE_UNITS.SURFACE, 'prefixes': PREFIXES.NONE, 'value': 25.29295, 'offset': 0}, // 25.29295 m2 - {'name': 'sqch', 'base': BASE_UNITS.SURFACE, 'prefixes': PREFIXES.NONE, 'value': 404.6873, 'offset': 0}, // 404.6873 m2 - {'name': 'sqmil', 'base': BASE_UNITS.SURFACE, 'prefixes': PREFIXES.NONE, 'value': 6.4516e-10, 'offset': 0}, // 6.4516 * 10^-10 m2 - - // Volume - {'name': 'm3', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.SHORT, 'value': 1, 'offset': 0}, - {'name': 'L', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.SHORT, 'value': 0.001, 'offset': 0}, // litre - {'name': 'litre', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.LONG, 'value': 0.001, 'offset': 0}, - {'name': 'cuin', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 1.6387064e-5, 'offset': 0}, // 1.6387064e-5 m3 - {'name': 'cuft', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.028316846592, 'offset': 0}, // 28.316 846 592 L - {'name': 'cuyd', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.764554857984, 'offset': 0}, // 764.554 857 984 L - {'name': 'teaspoon', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.000005, 'offset': 0}, // 5 mL - {'name': 'tablespoon', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.000015, 'offset': 0}, // 15 mL - //{'name': 'cup', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.000240, 'offset': 0}, // 240 mL // not possible, we have already another cup - - // Liquid volume - {'name': 'minim', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.00000006161152, 'offset': 0}, // 0.06161152 mL - {'name': 'fluiddram', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0000036966911, 'offset': 0}, // 3.696691 mL - {'name': 'fluidounce', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.00002957353, 'offset': 0}, // 29.57353 mL - {'name': 'gill', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0001182941, 'offset': 0}, // 118.2941 mL - {'name': 'cup', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0002365882, 'offset': 0}, // 236.5882 mL - {'name': 'pint', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0004731765, 'offset': 0}, // 473.1765 mL - {'name': 'quart', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0009463529, 'offset': 0}, // 946.3529 mL - {'name': 'gallon', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.003785412, 'offset': 0}, // 3.785412 L - {'name': 'beerbarrel', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.1173478, 'offset': 0}, // 117.3478 L - {'name': 'oilbarrel', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.1589873, 'offset': 0}, // 158.9873 L - {'name': 'hogshead', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.2384810, 'offset': 0}, // 238.4810 L - - //{'name': 'min', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.00000006161152, 'offset': 0}, // 0.06161152 mL // min is already in use as minute - {'name': 'fldr', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0000036966911, 'offset': 0}, // 3.696691 mL - {'name': 'floz', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.00002957353, 'offset': 0}, // 29.57353 mL - {'name': 'gi', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0001182941, 'offset': 0}, // 118.2941 mL - {'name': 'cp', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0002365882, 'offset': 0}, // 236.5882 mL - {'name': 'pt', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0004731765, 'offset': 0}, // 473.1765 mL - {'name': 'qt', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0009463529, 'offset': 0}, // 946.3529 mL - {'name': 'gal', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.003785412, 'offset': 0}, // 3.785412 L - {'name': 'bbl', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.1173478, 'offset': 0}, // 117.3478 L - {'name': 'obl', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.1589873, 'offset': 0}, // 158.9873 L - //{'name': 'hogshead', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.2384810, 'offset': 0}, // 238.4810 L // TODO: hh? - - // Mass - {'name': 'g', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.SHORT, 'value': 0.001, 'offset': 0}, - {'name': 'gram', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.LONG, 'value': 0.001, 'offset': 0}, - - {'name': 'ton', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.SHORT, 'value': 907.18474, 'offset': 0}, - {'name': 'tonne', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.SHORT, 'value': 1000, 'offset': 0}, - - {'name': 'grain', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 64.79891e-6, 'offset': 0}, - {'name': 'dram', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 1.7718451953125e-3, 'offset': 0}, - {'name': 'ounce', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 28.349523125e-3, 'offset': 0}, - {'name': 'poundmass', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 453.59237e-3, 'offset': 0}, - {'name': 'hundredweight', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 45.359237, 'offset': 0}, - {'name': 'stick', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 115e-3, 'offset': 0}, - - {'name': 'gr', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 64.79891e-6, 'offset': 0}, - {'name': 'dr', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 1.7718451953125e-3, 'offset': 0}, - {'name': 'oz', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 28.349523125e-3, 'offset': 0}, - {'name': 'lbm', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 453.59237e-3, 'offset': 0}, - {'name': 'cwt', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 45.359237, 'offset': 0}, - - // Time - {'name': 's', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.SHORT, 'value': 1, 'offset': 0}, - {'name': 'min', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.NONE, 'value': 60, 'offset': 0}, - {'name': 'h', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.NONE, 'value': 3600, 'offset': 0}, - {'name': 'seconds', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.LONG, 'value': 1, 'offset': 0}, - {'name': 'second', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.LONG, 'value': 1, 'offset': 0}, - {'name': 'sec', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.LONG, 'value': 1, 'offset': 0}, - {'name': 'minutes', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.NONE, 'value': 60, 'offset': 0}, - {'name': 'minute', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.NONE, 'value': 60, 'offset': 0}, - {'name': 'hours', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.NONE, 'value': 3600, 'offset': 0}, - {'name': 'hour', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.NONE, 'value': 3600, 'offset': 0}, - {'name': 'day', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.NONE, 'value': 86400, 'offset': 0}, - {'name': 'days', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.NONE, 'value': 86400, 'offset': 0}, - - // Angles - {'name': 'rad', 'base': BASE_UNITS.ANGLE, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0}, - {'name': 'deg', 'base': BASE_UNITS.ANGLE, 'prefixes': PREFIXES.NONE, 'value': 0.017453292519943295769236907684888, 'offset': 0}, // deg = rad / (2*pi) * 360 = rad / 0.017453292519943295769236907684888 - {'name': 'grad', 'base': BASE_UNITS.ANGLE, 'prefixes': PREFIXES.NONE, 'value': 0.015707963267948966192313216916399, 'offset': 0}, // grad = rad / (2*pi) * 400 = rad / 0.015707963267948966192313216916399 - {'name': 'cycle', 'base': BASE_UNITS.ANGLE, 'prefixes': PREFIXES.NONE, 'value': 6.2831853071795864769252867665793, 'offset': 0}, // cycle = rad / (2*pi) = rad / 6.2831853071795864769252867665793 - - // Electric current - {'name': 'A', 'base': BASE_UNITS.CURRENT, 'prefixes': PREFIXES.SHORT, 'value': 1, 'offset': 0}, - {'name': 'ampere', 'base': BASE_UNITS.CURRENT, 'prefixes': PREFIXES.LONG, 'value': 1, 'offset': 0}, - - // Temperature - // K(C) = °C + 273.15 - // K(F) = (°F + 459.67) / 1.8 - // K(R) = °R / 1.8 - {'name': 'K', 'base': BASE_UNITS.TEMPERATURE, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0}, - {'name': 'degC', 'base': BASE_UNITS.TEMPERATURE, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 273.15}, - {'name': 'degF', 'base': BASE_UNITS.TEMPERATURE, 'prefixes': PREFIXES.NONE, 'value': 1/1.8, 'offset': 459.67}, - {'name': 'degR', 'base': BASE_UNITS.TEMPERATURE, 'prefixes': PREFIXES.NONE, 'value': 1/1.8, 'offset': 0}, - {'name': 'kelvin', 'base': BASE_UNITS.TEMPERATURE, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0}, - {'name': 'celsius', 'base': BASE_UNITS.TEMPERATURE, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 273.15}, - {'name': 'fahrenheit', 'base': BASE_UNITS.TEMPERATURE, 'prefixes': PREFIXES.NONE, 'value': 1/1.8, 'offset': 459.67}, - {'name': 'rankine', 'base': BASE_UNITS.TEMPERATURE, 'prefixes': PREFIXES.NONE, 'value': 1/1.8, 'offset': 0}, - - // amount of substance - {'name': 'mol', 'base': BASE_UNITS.AMOUNT_OF_SUBSTANCE, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0}, - {'name': 'mole', 'base': BASE_UNITS.AMOUNT_OF_SUBSTANCE, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0}, - - // luminous intensity - {'name': 'cd', 'base': BASE_UNITS.LUMINOUS_INTENSITY, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0}, - {'name': 'candela', 'base': BASE_UNITS.LUMINOUS_INTENSITY, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0}, - // TODO: units STERADIAN - //{'name': 'sr', 'base': BASE_UNITS.STERADIAN, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0}, - //{'name': 'steradian', 'base': BASE_UNITS.STERADIAN, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0}, - - // Force - {'name': 'N', 'base': BASE_UNITS.FORCE, 'prefixes': PREFIXES.SHORT, 'value': 1, 'offset': 0}, - {'name': 'newton', 'base': BASE_UNITS.FORCE, 'prefixes': PREFIXES.LONG, 'value': 1, 'offset': 0}, - {'name': 'lbf', 'base': BASE_UNITS.FORCE, 'prefixes': PREFIXES.NONE, 'value': 4.4482216152605, 'offset': 0}, - {'name': 'poundforce', 'base': BASE_UNITS.FORCE, 'prefixes': PREFIXES.NONE, 'value': 4.4482216152605, 'offset': 0}, - - // Binary - {'name': 'b', 'base': BASE_UNITS.BIT, 'prefixes': PREFIXES.BINARY_SHORT, 'value': 1, 'offset': 0}, - {'name': 'bits', 'base': BASE_UNITS.BIT, 'prefixes': PREFIXES.BINARY_LONG, 'value': 1, 'offset': 0}, - {'name': 'B', 'base': BASE_UNITS.BIT, 'prefixes': PREFIXES.BINARY_SHORT, 'value': 8, 'offset': 0}, - {'name': 'bytes', 'base': BASE_UNITS.BIT, 'prefixes': PREFIXES.BINARY_LONG, 'value': 8, 'offset': 0} -]; - -Unit.PREFIXES = PREFIXES; -Unit.BASE_UNITS = BASE_UNITS; -Unit.UNITS = UNITS; - - -// exports -module.exports = Unit; - -// to trick my IDE which doesn't get it -exports.isUnit = Unit.isUnit; -exports.isPlainUnit = Unit.isPlainUnit; -exports.parse = Unit.parse; - -util.types.addType('unit', Unit); diff --git a/src/type/collection.js b/src/type/collection.js deleted file mode 100644 index f6b6101f1..000000000 --- a/src/type/collection.js +++ /dev/null @@ -1,228 +0,0 @@ -var util = require('../util/index.js'), - - Matrix = require('./Matrix.js'), - Range = require('./Range.js'), - - isArray = Array.isArray, - isString = util.string.isString; - -// utility methods for strings, objects, and arrays - -/** - * Convert function arguments to an array. Arguments can have the following - * signature: - * fn() - * fn(n) - * fn(m, n, p, ...) - * fn([m, n, p, ...]) - * @param {...Number | Array | Matrix} args - * @returns {Array} array - */ -exports.argsToArray = function argsToArray(args) { - var array; - if (args.length == 0) { - // fn() - array = []; - } - else if (args.length == 1) { - // fn(n) - // fn([m, n, p, ...]) - array = args[0]; - if (array instanceof Matrix) { - array = array.toVector(); - } - if (array instanceof Range) { - array = array.valueOf(); - } - if (!isArray(array)) { - array = [array]; - } - } - else { - // fn(m, n, p, ...) - /* TODO: cleanup - array = []; - for (var i = 0; i < args.length; i++) { - array[i] = args[i]; - } - */ - array = Array.prototype.slice.apply(args); - } - return array; -}; - - -/** - * Test whether a value is a collection: an Array, Matrix, or Range - * @param {*} x - * @returns {boolean} isCollection - */ -exports.isCollection = function isCollection (x) { - return (isArray(x) || (x instanceof Matrix) || (x instanceof Range)); -}; - -// TODO: write the map, deepMap, map2, and deepMap2 functions in a more concise way - -/** - * Execute function fn element wise for each element in array. - * Returns an array with the results - * @param {Array | Matrix | Range} array - * @param {function} fn - * @return {Array | Matrix} res - */ -exports.map = function map(array, fn) { - if (array && array.map) { - return array.map(function (x) { - return fn(x); - }); - } - else { - throw new TypeError('Array expected'); - } -}; - -/** - * Execute function fn element wise for each element in array and any nested - * array - * Returns an array with the results - * @param {Array | Matrix | Range} array - * @param {function} fn - * @return {Array | Matrix} res - */ -exports.deepMap = function deepMap(array, fn) { - if (array && array.map) { - return array.map(function (x) { - return deepMap(x, fn); - }); - } - else { - return fn(array); - } -}; - -/** - * Execute function fn element wise for each entry in two given arrays, or - * for a (scalar) object and array pair. Returns an array with the results - * @param {Array | Matrix | Range | Object} array1 - * @param {Array | Matrix | Range | Object} array2 - * @param {function} fn - * @return {Array | Matrix} res - */ -exports.map2 = function map2(array1, array2, fn) { - var res, len, i; - - // handle Matrix - if (array1 instanceof Matrix || array2 instanceof Matrix) { - return new Matrix(map2(array1.valueOf(), array2.valueOf(), fn)); - } - - // handle Range - if (array1 instanceof Range || array2 instanceof Range) { - // TODO: exports.map2 does not utilize Range.map - return map2(array1.valueOf(), array2.valueOf(), fn); - } - - if (isArray(array1)) { - if (isArray(array2)) { - // fn(array, array) - if (array1.length != array2.length) { - throw new RangeError('Dimension mismatch ' + - '(' + array1.length + ' != ' + array2.length + ')'); - } - - res = []; - len = array1.length; - for (i = 0; i < len; i++) { - res[i] = fn(array1[i], array2[i]); - } - } - else { - // fn(array, object) - res = []; - len = array1.length; - for (i = 0; i < len; i++) { - res[i] = fn(array1[i], array2); - } - } - } - else { - if (isArray(array2)) { - // fn(object, array) - res = []; - len = array2.length; - for (i = 0; i < len; i++) { - res[i] = fn(array1, array2[i]); - } - } - else { - // fn(object, object) - res = fn(array1, array2); - } - } - - return res; -}; - -/** - * Execute function fn element wise for each entry in two given arrays, - * and for any nested array. Objects can also be scalar objects. - * Returns an array with the results. - * @param {Array | Matrix | Range | Object} array1 - * @param {Array | Matrix | Range | Object} array2 - * @param {function} fn - * @return {Array | Matrix} res - */ -exports.deepMap2 = function deepMap2(array1, array2, fn) { - var res, len, i; - - // handle Matrix - if (array1 instanceof Matrix || array2 instanceof Matrix) { - return new Matrix(deepMap2(array1.valueOf(), array2.valueOf(), fn)); - } - - // handle Range - if (array1 instanceof Range || array2 instanceof Range) { - // TODO: util.deepMap2 does not utilize Range.map - return deepMap2(array1.valueOf(), array2.valueOf(), fn); - } - - if (isArray(array1)) { - if (isArray(array2)) { - // fn(array, array) - if (array1.length != array2.length) { - throw new RangeError('Dimension mismatch ' + - '(' + array1.length + ' != ' + array2.length + ')'); - } - - res = []; - len = array1.length; - for (i = 0; i < len; i++) { - res[i] = deepMap2(array1[i], array2[i], fn); - } - } - else { - // fn(array, object) - res = []; - len = array1.length; - for (i = 0; i < len; i++) { - res[i] = deepMap2(array1[i], array2, fn); - } - } - } - else { - if (isArray(array2)) { - // fn(object, array) - res = []; - len = array2.length; - for (i = 0; i < len; i++) { - res[i] = deepMap2(array1, array2[i], fn); - } - } - else { - // fn(object, object) - res = fn(array1, array2); - } - } - - return res; -}; diff --git a/src/type/index.js b/src/type/index.js deleted file mode 100644 index 1b1021889..000000000 --- a/src/type/index.js +++ /dev/null @@ -1,7 +0,0 @@ -exports.Complex = require('./Complex.js'); -exports.Range = require('./Range.js'); -exports.Matrix = require('./Matrix.js'); -exports.Unit = require('./Unit.js'); -exports.Help = require('./Help.js'); - -exports.collection = require('./collection.js'); diff --git a/src/util/array.js b/src/util/array.js deleted file mode 100644 index 368221c7c..000000000 --- a/src/util/array.js +++ /dev/null @@ -1,221 +0,0 @@ -var number = require('./number'), - string = require('./string'), - object = require('./object'), - types = require('./types'); - -/** - * Recursively calculate the size of a multi dimensional array. - * @param {Array} x - * @Return {Number[]} size - * @private - */ -function _size(x) { - if (Array.isArray(x)) { - var len = x.length; - - var size = len ? _size(x[0]) : []; - size.unshift(len); - return size; - } - else { - return []; - } -} - -/** - * Calculate the size of a multi dimensional array. - * All elements in the array are checked for matching dimensions using the - * method validate - * @param {Array} x - * @Return {Number[]} size - * @throws RangeError - */ -exports.size = function size (x) { - // calculate the size - var s = _size(x); - - // verify the size - exports.validate(x, s); - - return s; -}; - -/** - * Recursively validate whether each element in a multi dimensional array - * has a size corresponding to the provided size array. - * @param {Array} array Array to be validated - * @param {Number[]} size Array with the size of each dimension - * @param {Number} dim Current dimension - * @throws RangeError - * @private - */ -function _validate(array, size, dim) { - var i; - var len = array.length; - - if (len != size[dim]) { - throw new RangeError('Dimension mismatch (' + len + ' != ' + size[dim] + ')'); - } - - if (dim < size.length - 1) { - // recursively validate each child array - var dimNext = dim + 1; - for (i = 0; i < len; i++) { - var child = array[i]; - if (!Array.isArray(child)) { - throw new RangeError('Dimension mismatch ' + - '(' + (size.length - 1) + ' < ' + size.length + ')'); - } - _validate(array[i], size, dimNext); - } - } - else { - // last dimension. none of the childs may be an array - for (i = 0; i < len; i++) { - if (Array.isArray(array[i])) { - throw new RangeError('Dimension mismatch ' + - '(' + (size.length + 1) + ' > ' + size.length + ')'); - } - } - } -} - -/** - * Validate whether each element in a multi dimensional array has - * a size corresponding to the provided size array. - * @param {Array} array Array to be validated - * @param {Number[]} size Array with the size of each dimension - * @throws RangeError - */ -exports.validate = function validate(array, size) { - var isScalar = (size.length == 0); - if (isScalar) { - // scalar - if (Array.isArray(array)) { - throw new RangeError('Dimension mismatch (' + array.length + ' != 0)'); - } - } - else { - // array - _validate(array, size, 0); - } -}; - -/** - * Test whether index is an integer number with index >= 0 and index < length - * @param {*} index Zero-based index - * @param {Number} [length] Length of the array - */ -exports.validateIndex = function validateIndex (index, length) { - if (!number.isNumber(index) || !number.isInteger(index)) { - throw new TypeError('Index must be an integer (value: ' + index + ')'); - } - if (index < 0) { - throw new RangeError('Index out of range (' + index + ' < 0)'); - } - if (length !== undefined && index >= length) { - throw new RangeError('Index out of range (' + index + ' >= ' + length + ')'); - } -}; - -/** - * Recursively resize a multi dimensional array - * @param {Array} array Array to be resized - * @param {Number[]} size Array with the size of each dimension - * @param {Number} dim Current dimension - * @param {*} [defaultValue] Value to be filled in in new entries, - * 0 by default. - * @private - */ -function _resize (array, size, dim, defaultValue) { - if (!Array.isArray(array)) { - throw new TypeError('Array expected'); - } - - var len = array.length, - newLen = size[dim]; - - if (len != newLen) { - if(newLen > array.length) { - // enlarge - for (var i = array.length; i < newLen; i++) { - array[i] = defaultValue ? object.clone(defaultValue) : 0; - } - } - else { - // shrink - array.length = size[dim]; - } - len = array.length; - } - - if (dim < size.length - 1) { - // recursively validate each child array - var dimNext = dim + 1; - for (i = 0; i < len; i++) { - child = array[i]; - if (!Array.isArray(child)) { - child = [child]; - array[i] = child; - } - _resize(child, size, dimNext, defaultValue); - } - } - else { - // last dimension - for (i = 0; i < len; i++) { - var child = array[i]; - while (Array.isArray(child)) { - child = child[0]; - } - array[i] = child; - } - } -} - -/** - * Resize a multi dimensional array - * @param {Array} array Array to be resized - * @param {Array.} size Array with the size of each dimension - * @param {*} [defaultValue] Value to be filled in in new entries, - * 0 by default - */ -exports.resize = function resize(array, size, defaultValue) { - // TODO: what to do with scalars, when size=[] ? - - // check the type of size - if (!Array.isArray(size)) { - throw new TypeError('Size must be an array (size is ' + types.type(size) + ')'); - } - - // check whether size contains positive integers - size.forEach(function (value) { - if (!number.isNumber(value) || !number.isInteger(value) || value < 0) { - throw new TypeError('Invalid size, must contain positive integers ' + - '(size: ' + string.format(size) + ')'); - } - }); - - /* TODO: cleanup - var hasZeros = (size.indexOf(0) != -1); - if (hasZeros) { - // array where all dimensions are zero - size.forEach(function (value) { - if (value != 0) { - throw new RangeError('Invalid size, all dimensions must be ' + - 'either zero or non-zero (size: ' + string.format(size) + ')'); - } - }); - } - */ - - // recursively resize - _resize(array, size, 0, defaultValue); -}; - -/** - * Test whether an object is an array - * @param {*} value - * @return {Boolean} isArray - */ -exports.isArray = Array.isArray; \ No newline at end of file diff --git a/src/util/boolean.js b/src/util/boolean.js deleted file mode 100644 index dab950308..000000000 --- a/src/util/boolean.js +++ /dev/null @@ -1,8 +0,0 @@ -/** - * Test whether value is a Boolean - * @param {*} value - * @return {Boolean} isBoolean - */ -exports.isBoolean = function isBoolean(value) { - return (value instanceof Boolean) || (typeof value == 'boolean'); -}; diff --git a/src/util/error.js b/src/util/error.js deleted file mode 100644 index f30a3f77c..000000000 --- a/src/util/error.js +++ /dev/null @@ -1,47 +0,0 @@ -var types = require('./types.js'); - -/** - * Create a TypeError with message: - * 'Function does not support a parameter of type '; - * @param {String} name Function name - * @param {*} value1 - * @param {*} [value2] - * @extends TypeError - */ -exports.UnsupportedTypeError = function UnsupportedTypeError(name, value1, value2) { - if (arguments.length == 2) { - var t = types.type(value1); - this.message = 'Function ' + name + '(' + t + ') not supported'; - } - else if (arguments.length > 2) { - var args = []; - for (var i = 1; i < arguments.length; i++) { - args.push(types.type(arguments[i])); - } - this.message = 'Function ' + name + '(' + args.join(', ') + ') not supported'; - } - else { - this.message = 'Unsupported parameter in function ' + name; - } -}; - -exports.UnsupportedTypeError.prototype = new TypeError(); -exports.UnsupportedTypeError.prototype.name = 'UnsupportedTypeError'; - -/** - * Create a syntax error with the message: - * 'Wrong number of arguments in function ( provided, - expected)' - * @param {String} name Function name - * @param {Number} count Actual argument count - * @param {Number} min Minimum required argument count - * @param {Number} [max] Maximum required argument count - * @extends SyntaxError - */ -exports.ArgumentsError = function ArgumentsError(name, count, min, max) { - this.message = 'Wrong number of arguments in function ' + name + - ' (' + count + ' provided, ' + - min + ((max != undefined) ? ('-' + max) : '') + ' expected)'; -}; - -exports.ArgumentsError.prototype = new SyntaxError(); -exports.ArgumentsError.prototype.name = 'ArgumentError'; diff --git a/src/util/index.js b/src/util/index.js deleted file mode 100644 index ea420bdda..000000000 --- a/src/util/index.js +++ /dev/null @@ -1,7 +0,0 @@ -exports.array = require('./array'); -exports.boolean = require('./boolean'); -exports.error = require('./error'); -exports.number = require('./number'); -exports.object = require('./object'); -exports.string = require('./string'); -exports.types = require('./types'); diff --git a/src/util/number.js b/src/util/number.js deleted file mode 100644 index 578aa1213..000000000 --- a/src/util/number.js +++ /dev/null @@ -1,87 +0,0 @@ -var options = require('../options.js'); - -/** - * Test whether value is a Number - * @param {*} value - * @return {Boolean} isNumber - */ -exports.isNumber = function isNumber(value) { - return (value instanceof Number) || (typeof value == 'number'); -}; - -/** - * Check if a number is integer - * @param {Number} value - * @return {Boolean} isInteger - */ -exports.isInteger = function isInteger(value) { - return (value == Math.round(value)); -}; - -/** - * Convert a number to a formatted string representation. - * @param {Number} value The value to be formatted - * @param {Number} [precision] number of digits in formatted output - * @return {String} formattedValue The formatted value - */ -exports.format = function format(value, precision) { - if (value === Infinity) { - return 'Infinity'; - } - else if (value === -Infinity) { - return '-Infinity'; - } - else if (isNaN(value)) { - return 'NaN'; - } - - // TODO: what is a nice limit for non-scientific values? - var abs = Math.abs(value); - if ( (abs > 0.001 && abs < 100000) || abs == 0.0 ) { - // round the value to a limited number of precision - return exports.toPrecision(value, precision); - } - else { - // scientific notation - var exp = Math.round(Math.log(abs) / Math.LN10); - var v = value / (Math.pow(10.0, exp)); - return exports.toPrecision(v, precision) + 'e' + exp; - } -}; - -/** - * Calculate the sign of a number - * @param {Number} x - * @returns {*} - */ -exports.sign = function sign (x) { - if (x > 0) { - return 1; - } - else if (x < 0) { - return -1; - } - else { - return 0; - } -}; - -/** - * Round a value to a maximum number of precision. Trailing zeros will be - * removed. - * @param {Number} value - * @param {Number} [precision] Number of digits in formatted output - * @returns {string} str - */ -exports.toPrecision = function toPrecision (value, precision) { - if (precision === undefined) { - precision = options.precision; - } - - return value.toPrecision(precision).replace(_trailingZeros, function (a, b, c) { - return a.substring(0, a.length - (b.length ? 0 : 1) - c.length); - }); -}; - -/** @private */ -var _trailingZeros = /\.(\d*?)(0+)$/g; diff --git a/src/util/object.js b/src/util/object.js deleted file mode 100644 index c5d4b0faf..000000000 --- a/src/util/object.js +++ /dev/null @@ -1,131 +0,0 @@ -var number = require('./number.js'), - string = require('./string.js'), - bool = require('./boolean.js'); - -/** - * Clone an object - * - * clone(x) - * - * @param {*} x - * @return {*} clone - */ -exports.clone = function clone(x) { - if (x == null) { - // null or undefined - return x; - } - - if (typeof(x.clone) === 'function') { - return x.clone(); - } - - if (number.isNumber(x) || string.isString(x) || bool.isBoolean(x)) { - return x; - } - - if (Array.isArray(x)) { - return x.map(function (value) { - return clone(value); - }); - } - - if (x instanceof Object) { - var m = {}; - for (var key in x) { - if (x.hasOwnProperty(key)) { - m[key] = clone(x[key]); - } - } - } - - throw new TypeError('Cannot clone ' + x); -}; - -/** - * Extend object a with the properties of object b - * @param {Object} a - * @param {Object} b - * @return {Object} a - */ -exports.extend = function extend (a, b) { - for (var prop in b) { - if (b.hasOwnProperty(prop)) { - a[prop] = b[prop]; - } - } - return a; -}; - -/** - * Deep extend an object a with the properties of object b - * @param {Object} a - * @param {Object} b - * @returns {Object} - */ -exports.deepExtend = function deepExtend (a, b) { - for (var prop in b) { - if (b.hasOwnProperty(prop)) { - if (b[prop] && b[prop].constructor === Object) { - if (a[prop] === undefined) { - a[prop] = {}; - } - if (a[prop].constructor === Object) { - deepExtend(a[prop], b[prop]); - } - else { - a[prop] = b[prop]; - } - } else { - a[prop] = b[prop]; - } - } - } - return a; -}; - -/** - * Deep test equality of all fields in two pairs of arrays or objects. - * @param {Array | Object} a - * @param {Array | Object} b - * @returns {boolean} - */ -exports.deepEqual = function deepEqual (a, b) { - var prop, i, len; - if (Array.isArray(a)) { - if (!Array.isArray(b)) { - return false; - } - - for (i = 0, len = a.length; i < len; i++) { - if (!exports.deepEqual(a[i], b[i])) { - return false; - } - } - return true; - } - else if (a instanceof Object) { - if (Array.isArray(b) || !(b instanceof Object)) { - return false; - } - - for (prop in a) { - if (a.hasOwnProperty(prop)) { - if (!exports.deepEqual(a[prop], b[prop])) { - return false; - } - } - } - for (prop in b) { - if (b.hasOwnProperty(prop)) { - if (!exports.deepEqual(a[prop], b[prop])) { - return false; - } - } - } - return true; - } - else { - return (a.valueOf() == b.valueOf()); - } -}; diff --git a/src/util/string.js b/src/util/string.js deleted file mode 100644 index 072e70241..000000000 --- a/src/util/string.js +++ /dev/null @@ -1,150 +0,0 @@ -var number = require('./number.js'); - -/** - * Test whether value is a String - * @param {*} value - * @return {Boolean} isString - */ -exports.isString = function isString(value) { - return (value instanceof String) || (typeof value == 'string'); -}; - -/** - * Check if a text ends with a certain string. - * @param {String} text - * @param {String} search - */ -exports.endsWith = function endsWith(text, search) { - var start = text.length - search.length; - var end = text.length; - return (text.substring(start, end) === search); -}; - -/** - * Format a value of any type into a string. Interpolate values into the string. - * Numbers are rounded off to a maximum number of 5 digits by default. - * Usage: - * math.format(value) - * math.format(template, object) - * - * Example usage: - * math.format(2/7); // '0.28571' - * math.format(new Complex(2, 3)); // '2 + 3i' - * math.format('Hello $name! The date is $date', { - * name: 'user', - * date: new Date().toISOString().substring(0, 10) - * }); // 'hello user! The date is 2013-03-23' - * - * @param {String | *} template Template or value - * @param {Object} [values] - * @return {String} str - */ -exports.format = function format(template, values) { - var num = arguments.length; - - if (num == 1) { - // just format a value as string - var value = arguments[0]; - if (number.isNumber(value)) { - return number.format(value); - } - - if (Array.isArray(value)) { - return formatArray(value); - } - - if (exports.isString(value)) { - return '"' + value + '"'; - } - - if (value instanceof Object) { - return value.toString(); - } - - return String(value); - } - else { - if (!exports.isString(template)) { - throw new TypeError('String expected as first parameter in function format'); - } - if (!(values instanceof Object)) { - throw new TypeError('Object expected as second parameter in function format'); - } - - // format values into a string - return template.replace(/\$([\w\.]+)/g, function (original, key) { - var keys = key.split('.'); - var value = values[keys.shift()]; - while (keys.length && value != undefined) { - var k = keys.shift(); - value = k ? value[k] : value + '.'; - } - return value != undefined ? value : original; - } - ); - } -}; - -/** - * Recursively format an n-dimensional matrix - * Example output: "[[1, 2], [3, 4]]" - * @param {Array} array - * @returns {String} str - */ -function formatArray (array) { - if (Array.isArray(array)) { - var str = '['; - var len = array.length; - for (var i = 0; i < len; i++) { - if (i != 0) { - str += ', '; - } - str += formatArray(array[i]); - } - str += ']'; - return str; - } - else { - return exports.format(array); - } -} - -/** - * Recursively format an n-dimensional array, output looks like - * "[1, 2, 3]" - * @param {Array} array - * @returns {string} str - */ -/* TODO: use function formatArray2d or remove it -function formatArray2d (array) { - var str = '['; - var s = size(array); - - if (s.length != 2) { - throw new RangeError('Array must be two dimensional (size: ' + - formatArray(s) + ')'); - } - - var rows = s[0]; - var cols = s[1]; - for (var r = 0; r < rows; r++) { - if (r != 0) { - str += '; '; - } - - var row = array[r]; - for (var c = 0; c < cols; c++) { - if (c != 0) { - str += ', '; - } - var cell = row[c]; - if (cell != undefined) { - str += exports.format(cell); - } - } - } - str += ']'; - - return str; -} -*/ \ No newline at end of file diff --git a/src/util/types.js b/src/util/types.js deleted file mode 100644 index 7b3d39fcb..000000000 --- a/src/util/types.js +++ /dev/null @@ -1,66 +0,0 @@ -/** - * Determine the type of a variable - * - * typeof(x) - * - * @param {*} x - * @return {String} type Lower case type, for example "number", "string", - * "array". - */ -exports.type = function type (x) { - var type = typeof x, - name; - - if (type == 'object') { - if (x == null) { - return 'null'; - } - if (x instanceof Boolean) { - return 'boolean'; - } - if (x instanceof Number) { - return 'number'; - } - if (x instanceof String) { - return 'string'; - } - if (Array.isArray(x)) { - return 'array'; - } - if (x instanceof Date) { - return 'date'; - } - if (x.constructor) { - // search data types - for (name in types) { - if (types.hasOwnProperty(name)) { - if (x.constructor == types[name]) { - return name.toLowerCase(); - } - } - } - - // try the constructors name as last resort - if (x.constructor.name) { - return x.constructor.name.toLowerCase(); - } - } - } - - return type; -}; - -/** - * Custom registered types, for example {'matrix': Matrix} - * @private - */ -var types = {}; - -/** - * Register a new type, for example addType('matrix', Matrix) - * @param {String} name Lower case name of the type - * @param {Function} type Prototype function of the type - */ -exports.addType = function addType (name, type) { - types[name] = type; -}; diff --git a/test/contstants.test.js b/test/contstants.test.js index 75b575788..8c142d845 100644 --- a/test/contstants.test.js +++ b/test/contstants.test.js @@ -1,5 +1,5 @@ var assert = require('assert'), - math = require('../src/index.js'), + math = require('../lib/index.js'), approx = require('../tools/approx.js'); // pi diff --git a/test/expr/parser.test.js b/test/expr/parser.test.js index c1e8d174d..0269c02da 100644 --- a/test/expr/parser.test.js +++ b/test/expr/parser.test.js @@ -2,7 +2,7 @@ var assert = require('assert'), approx = require('../../tools/approx.js'), - math = require('../../src/index.js'), + math = require('../../lib/index.js'), matrix = math.matrix, range = math.range, round = math.round; diff --git a/test/expr/scope.test.js b/test/expr/scope.test.js index e4848f37d..7b954f3fb 100644 --- a/test/expr/scope.test.js +++ b/test/expr/scope.test.js @@ -1,7 +1,7 @@ // test Scope var assert = require('assert'), approx = require('../../tools/approx.js'), - math = require('../../src/index.js'), + math = require('../../lib/index.js'), Scope = math.expr.Scope; describe('Scope', function() { diff --git a/test/function/arithmetic/abs.test.js b/test/function/arithmetic/abs.test.js index 63688406c..54d7f956d 100644 --- a/test/function/arithmetic/abs.test.js +++ b/test/function/arithmetic/abs.test.js @@ -1,6 +1,6 @@ // test abs var assert = require('assert'); -var math = require('../../../src/index.js'); +var math = require('../../../lib/index.js'); describe('abs', function () { diff --git a/test/function/arithmetic/add.test.js b/test/function/arithmetic/add.test.js index 47d8551bd..016c3e08d 100644 --- a/test/function/arithmetic/add.test.js +++ b/test/function/arithmetic/add.test.js @@ -1,6 +1,6 @@ // test add var assert = require('assert'); -var math = require('../../../src/index.js'); +var math = require('../../../lib/index.js'); describe('add', function() { diff --git a/test/function/arithmetic/ceil.test.js b/test/function/arithmetic/ceil.test.js index 772b7dcca..a8da29f51 100644 --- a/test/function/arithmetic/ceil.test.js +++ b/test/function/arithmetic/ceil.test.js @@ -1,7 +1,7 @@ // test ceil var assert = require('assert'), approx = require('../../../tools/approx.js'), - math = require('../../../src/index.js'), + math = require('../../../lib/index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/arithmetic/cube.test.js b/test/function/arithmetic/cube.test.js index 00600376f..4a6fd2441 100644 --- a/test/function/arithmetic/cube.test.js +++ b/test/function/arithmetic/cube.test.js @@ -1,6 +1,6 @@ // test cube var assert = require('assert'), - math = require('../../../src/index.js'), + math = require('../../../lib/index.js'), unit = math.unit, matrix = math.matrix, range = math.range, diff --git a/test/function/arithmetic/divide.test.js b/test/function/arithmetic/divide.test.js index b0dfca69f..b9315fe03 100644 --- a/test/function/arithmetic/divide.test.js +++ b/test/function/arithmetic/divide.test.js @@ -1,6 +1,6 @@ // test divide var assert = require('assert'); -math = require('../../../src/index.js'), +math = require('../../../lib/index.js'), approx = require('../../../tools/approx.js'), divide = math.divide, complex = math.complex; diff --git a/test/function/arithmetic/edivide.test.js b/test/function/arithmetic/edivide.test.js index 2e037f389..dd37641e7 100644 --- a/test/function/arithmetic/edivide.test.js +++ b/test/function/arithmetic/edivide.test.js @@ -1,6 +1,6 @@ // test edivide (element-wise divide) var assert = require('assert'); -math = require('../../../src/index.js'), +math = require('../../../lib/index.js'), approx = require('../../../tools/approx.js'), edivide = math.edivide, complex = math.complex; diff --git a/test/function/arithmetic/emultiply.test.js b/test/function/arithmetic/emultiply.test.js index 2afeb0d6f..e49cd0d34 100644 --- a/test/function/arithmetic/emultiply.test.js +++ b/test/function/arithmetic/emultiply.test.js @@ -1,6 +1,6 @@ // test emultiply (element-wise multiply) var assert = require('assert'), - math = require('../../../src/index.js'), + math = require('../../../lib/index.js'), approx = require('../../../tools/approx.js'), emultiply = math.emultiply, divide = math.divide, diff --git a/test/function/arithmetic/epow.test.js b/test/function/arithmetic/epow.test.js index 0819ad2f7..afa850c0b 100644 --- a/test/function/arithmetic/epow.test.js +++ b/test/function/arithmetic/epow.test.js @@ -1,7 +1,7 @@ // test exp var assert = require('assert'), approx = require('../../../tools/approx.js'), - math = require('../../../src/index.js'), + math = require('../../../lib/index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/arithmetic/equal.test.js b/test/function/arithmetic/equal.test.js index d82c5e3b5..cf3ae9333 100644 --- a/test/function/arithmetic/equal.test.js +++ b/test/function/arithmetic/equal.test.js @@ -1,6 +1,6 @@ // test equal var assert = require('assert'), - math = require('../../../src/index.js'), + math = require('../../../lib/index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/arithmetic/exp.test.js b/test/function/arithmetic/exp.test.js index 07c6c130e..80946ea4a 100644 --- a/test/function/arithmetic/exp.test.js +++ b/test/function/arithmetic/exp.test.js @@ -1,7 +1,7 @@ // test exp var assert = require('assert'), approx = require('../../../tools/approx.js'), - math = require('../../../src/index.js'), + math = require('../../../lib/index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/arithmetic/fix.test.js b/test/function/arithmetic/fix.test.js index d861e899d..0f8c4b6aa 100644 --- a/test/function/arithmetic/fix.test.js +++ b/test/function/arithmetic/fix.test.js @@ -1,7 +1,7 @@ // test fix var assert = require('assert'), approx = require('../../../tools/approx.js'), - math = require('../../../src/index.js'), + math = require('../../../lib/index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/arithmetic/floor.test.js b/test/function/arithmetic/floor.test.js index c0dc14344..8f2c23f44 100644 --- a/test/function/arithmetic/floor.test.js +++ b/test/function/arithmetic/floor.test.js @@ -1,7 +1,7 @@ // test floor var assert = require('assert'), approx = require('../../../tools/approx.js'), - math = require('../../../src/index.js'), + math = require('../../../lib/index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/arithmetic/gcd.test.js b/test/function/arithmetic/gcd.test.js index 9eb9351a9..53a135da3 100644 --- a/test/function/arithmetic/gcd.test.js +++ b/test/function/arithmetic/gcd.test.js @@ -1,6 +1,6 @@ // test gcd var assert = require('assert'); -var math = require('../../../src/index.js'); +var math = require('../../../lib/index.js'); describe('gcd', function() { diff --git a/test/function/arithmetic/larger.test.js b/test/function/arithmetic/larger.test.js index 3004e8184..f84589e5c 100644 --- a/test/function/arithmetic/larger.test.js +++ b/test/function/arithmetic/larger.test.js @@ -1,6 +1,6 @@ // test larger var assert = require('assert'), - math = require('../../../src/index.js'), + math = require('../../../lib/index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/arithmetic/largereq.test.js b/test/function/arithmetic/largereq.test.js index 3cc6288f0..e14399a2a 100644 --- a/test/function/arithmetic/largereq.test.js +++ b/test/function/arithmetic/largereq.test.js @@ -1,6 +1,6 @@ // test largereq var assert = require('assert'), - math = require('../../../src/index.js'), + math = require('../../../lib/index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/arithmetic/lcm.test.js b/test/function/arithmetic/lcm.test.js index 30879fd6f..2373b5456 100644 --- a/test/function/arithmetic/lcm.test.js +++ b/test/function/arithmetic/lcm.test.js @@ -1,5 +1,5 @@ var assert = require('assert'); -var math = require('../../../src/index.js'); +var math = require('../../../lib/index.js'); describe('lcm', function() { diff --git a/test/function/arithmetic/log.test.js b/test/function/arithmetic/log.test.js index ef1b56ac1..46b19e788 100644 --- a/test/function/arithmetic/log.test.js +++ b/test/function/arithmetic/log.test.js @@ -1,7 +1,7 @@ // test exp var assert = require('assert'), approx = require('../../../tools/approx.js'), - math = require('../../../src/index.js'), + math = require('../../../lib/index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/arithmetic/log10.test.js b/test/function/arithmetic/log10.test.js index c5b41f468..f03747b67 100644 --- a/test/function/arithmetic/log10.test.js +++ b/test/function/arithmetic/log10.test.js @@ -1,7 +1,7 @@ // test exp var assert = require('assert'), approx = require('../../../tools/approx.js'), - math = require('../../../src/index.js'), + math = require('../../../lib/index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/arithmetic/mod.test.js b/test/function/arithmetic/mod.test.js index e381f1211..412142e8a 100644 --- a/test/function/arithmetic/mod.test.js +++ b/test/function/arithmetic/mod.test.js @@ -1,7 +1,7 @@ // test mod var assert = require('assert'), approx = require('../../../tools/approx.js'), - math = require('../../../src/index.js'), + math = require('../../../lib/index.js'), matrix = math.matrix, range = math.range, mod = math.mod; diff --git a/test/function/arithmetic/multiply.test.js b/test/function/arithmetic/multiply.test.js index c434f4441..931fc1f11 100644 --- a/test/function/arithmetic/multiply.test.js +++ b/test/function/arithmetic/multiply.test.js @@ -1,6 +1,6 @@ // test multiply var assert = require('assert'), - math = require('../../../src/index.js'), + math = require('../../../lib/index.js'), approx = require('../../../tools/approx.js'), multiply = math.multiply, divide = math.divide, diff --git a/test/function/arithmetic/pow.test.js b/test/function/arithmetic/pow.test.js index 431aa36b7..15feae36b 100644 --- a/test/function/arithmetic/pow.test.js +++ b/test/function/arithmetic/pow.test.js @@ -1,7 +1,7 @@ // test exp var assert = require('assert'), approx = require('../../../tools/approx.js'), - math = require('../../../src/index.js'), + math = require('../../../lib/index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/arithmetic/round.test.js b/test/function/arithmetic/round.test.js index 20f05dccf..d6578886e 100644 --- a/test/function/arithmetic/round.test.js +++ b/test/function/arithmetic/round.test.js @@ -1,6 +1,6 @@ // test round var assert = require('assert'); -var math = require('../../../src/index.js'); +var math = require('../../../lib/index.js'); describe('round', function() { diff --git a/test/function/arithmetic/sign.test.js b/test/function/arithmetic/sign.test.js index 0140986c9..1380019a7 100644 --- a/test/function/arithmetic/sign.test.js +++ b/test/function/arithmetic/sign.test.js @@ -1,6 +1,6 @@ // test sign var assert = require('assert'); -var math = require('../../../src/index.js'); +var math = require('../../../lib/index.js'); describe('sign', function() { diff --git a/test/function/arithmetic/smaller.test.js b/test/function/arithmetic/smaller.test.js index 3a7136a4f..c9b2d90f4 100644 --- a/test/function/arithmetic/smaller.test.js +++ b/test/function/arithmetic/smaller.test.js @@ -1,6 +1,6 @@ // test smaller var assert = require('assert'), - math = require('../../../src/index.js'), + math = require('../../../lib/index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/arithmetic/smallereq.test.js b/test/function/arithmetic/smallereq.test.js index 950954d09..c6ecc0196 100644 --- a/test/function/arithmetic/smallereq.test.js +++ b/test/function/arithmetic/smallereq.test.js @@ -1,6 +1,6 @@ // test smaller var assert = require('assert'), - math = require('../../../src/index.js'), + math = require('../../../lib/index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/arithmetic/sqrt.test.js b/test/function/arithmetic/sqrt.test.js index 61d1e84c2..6ecc69fc1 100644 --- a/test/function/arithmetic/sqrt.test.js +++ b/test/function/arithmetic/sqrt.test.js @@ -1,7 +1,7 @@ // test sqrt var assert = require('assert'), approx = require('../../../tools/approx.js'), - math = require('../../../src/index.js'); + math = require('../../../lib/index.js'); describe('sqrt', function() { diff --git a/test/function/arithmetic/square.test.js b/test/function/arithmetic/square.test.js index 5ca68d0b8..1f226c76b 100644 --- a/test/function/arithmetic/square.test.js +++ b/test/function/arithmetic/square.test.js @@ -1,6 +1,6 @@ // test square var assert = require('assert'), - math = require('../../../src/index.js'), + math = require('../../../lib/index.js'), unit = math.unit, matrix = math.matrix, range = math.range, diff --git a/test/function/arithmetic/subtract.test.js b/test/function/arithmetic/subtract.test.js index 8a06755ab..c28ce61f7 100644 --- a/test/function/arithmetic/subtract.test.js +++ b/test/function/arithmetic/subtract.test.js @@ -1,6 +1,6 @@ // test subtract var assert = require('assert'); -var math = require('../../../src/index.js'); +var math = require('../../../lib/index.js'); describe('subtract', function() { diff --git a/test/function/arithmetic/unary.js b/test/function/arithmetic/unary.js index 200b11be6..6b3ea094c 100644 --- a/test/function/arithmetic/unary.js +++ b/test/function/arithmetic/unary.js @@ -1,6 +1,6 @@ // test unary minus var assert = require('assert'); -var math = require('../../../src/index.js'); +var math = require('../../../lib/index.js'); describe('unaryminus', function() { diff --git a/test/function/arithmetic/unequal.test.js b/test/function/arithmetic/unequal.test.js index 7790518cb..9067f3b48 100644 --- a/test/function/arithmetic/unequal.test.js +++ b/test/function/arithmetic/unequal.test.js @@ -1,6 +1,6 @@ // test equal var assert = require('assert'), - math = require('../../../src/index.js'), + math = require('../../../lib/index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/arithmetic/xgcd.test.js b/test/function/arithmetic/xgcd.test.js index 43f7cddc2..fb5dbdc68 100644 --- a/test/function/arithmetic/xgcd.test.js +++ b/test/function/arithmetic/xgcd.test.js @@ -1,6 +1,6 @@ // test xgcd var assert = require('assert'); -var math = require('../../../src/index.js'); +var math = require('../../../lib/index.js'); describe('xgcd', function() { diff --git a/test/function/complex/arg.test.js b/test/function/complex/arg.test.js index 1d3eb2dca..3fb5898b2 100644 --- a/test/function/complex/arg.test.js +++ b/test/function/complex/arg.test.js @@ -1,5 +1,5 @@ var assert = require('assert'); -var math = require('../../../src/index.js'); +var math = require('../../../lib/index.js'); describe('arg', function() { diff --git a/test/function/complex/conj.test.js b/test/function/complex/conj.test.js index 8343e928f..6f25903ec 100644 --- a/test/function/complex/conj.test.js +++ b/test/function/complex/conj.test.js @@ -1,5 +1,5 @@ var assert = require('assert'); -var math = require('../../../src/index.js'); +var math = require('../../../lib/index.js'); describe('conj', function() { diff --git a/test/function/complex/im.test.js b/test/function/complex/im.test.js index e723c61b2..bd05bd885 100644 --- a/test/function/complex/im.test.js +++ b/test/function/complex/im.test.js @@ -1,5 +1,5 @@ var assert = require('assert'); -var math = require('../../../src/index.js'); +var math = require('../../../lib/index.js'); describe('im', function() { diff --git a/test/function/complex/re.test.js b/test/function/complex/re.test.js index acbbb9199..b5b9d612b 100644 --- a/test/function/complex/re.test.js +++ b/test/function/complex/re.test.js @@ -1,5 +1,5 @@ var assert = require('assert'); -var math = require('../../../src/index.js'); +var math = require('../../../lib/index.js'); describe('re', function() { diff --git a/test/function/construction/boolean.test.js b/test/function/construction/boolean.test.js index 5a0f8e248..ac5c83403 100644 --- a/test/function/construction/boolean.test.js +++ b/test/function/construction/boolean.test.js @@ -1,5 +1,5 @@ var assert = require('assert'), - math = require('../../../src/index.js'), + math = require('../../../lib/index.js'), bool = math.boolean; describe('boolean', function() { diff --git a/test/function/construction/complex.test.js b/test/function/construction/complex.test.js index 27e89b11e..b35a2dd4e 100644 --- a/test/function/construction/complex.test.js +++ b/test/function/construction/complex.test.js @@ -1,5 +1,5 @@ var assert = require('assert'), - math = require('../../../src/index.js'), + math = require('../../../lib/index.js'), complex = math.complex; describe('complex', function() { diff --git a/test/function/construction/matrix.test.js b/test/function/construction/matrix.test.js index 6e07225b8..f3a952ac2 100644 --- a/test/function/construction/matrix.test.js +++ b/test/function/construction/matrix.test.js @@ -1,6 +1,6 @@ // test matrix construction var assert = require('assert'), - math = require('../../../src/index.js'), + math = require('../../../lib/index.js'), matrix = math.matrix; describe('matrix', function() { diff --git a/test/function/construction/number.test.js b/test/function/construction/number.test.js index 2d81381ca..c71d609e0 100644 --- a/test/function/construction/number.test.js +++ b/test/function/construction/number.test.js @@ -1,5 +1,5 @@ var assert = require('assert'), - math = require('../../../src/index.js'), + math = require('../../../lib/index.js'), approx = require('../../../tools/approx.js'), number = math.number; diff --git a/test/function/construction/range.test.js b/test/function/construction/range.test.js index 815a6e4af..9afae046f 100644 --- a/test/function/construction/range.test.js +++ b/test/function/construction/range.test.js @@ -1,5 +1,5 @@ var assert = require('assert'), - math = require('../../../src/index.js'), + math = require('../../../lib/index.js'), range = math.range; describe('range', function() { diff --git a/test/function/construction/string.test.js b/test/function/construction/string.test.js index 0e6ea63fc..21ea30c7e 100644 --- a/test/function/construction/string.test.js +++ b/test/function/construction/string.test.js @@ -1,5 +1,5 @@ var assert = require('assert'), - math = require('../../../src/index.js'), + math = require('../../../lib/index.js'), string = math.string; describe('string', function() { diff --git a/test/function/construction/unit.test.js b/test/function/construction/unit.test.js index eaefe92bf..8649f5063 100644 --- a/test/function/construction/unit.test.js +++ b/test/function/construction/unit.test.js @@ -1,5 +1,5 @@ var assert = require('assert'), - math = require('../../../src/index.js'), + math = require('../../../lib/index.js'), unit = math.unit; describe('unit', function() { diff --git a/test/function/example.test.js b/test/function/example.test.js index cf008df30..8b7887bb6 100644 --- a/test/function/example.test.js +++ b/test/function/example.test.js @@ -3,7 +3,7 @@ return; var assert = require('assert'), approx = require('../../tools/approx.js'), - math = require('../../src/index.js'), + math = require('../../lib/index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/matrix/concat.test.js b/test/function/matrix/concat.test.js index 026d7ee0a..3e387abb3 100644 --- a/test/function/matrix/concat.test.js +++ b/test/function/matrix/concat.test.js @@ -1,6 +1,6 @@ // test concat var assert = require('assert'); -var math = require('../../../src/index.js'); +var math = require('../../../lib/index.js'); assert.deepEqual(math.concat([1,2,3], [4]), [1,2,3,4]); assert.deepEqual(math.concat([[1],[2],[3]], [[4]], 0), [[1],[2],[3],[4]]); diff --git a/test/function/matrix/det.test.js b/test/function/matrix/det.test.js index d5b28a863..9a7163a7b 100644 --- a/test/function/matrix/det.test.js +++ b/test/function/matrix/det.test.js @@ -1,6 +1,6 @@ // test det var assert = require('assert'); -var math = require('../../../src/index.js'); +var math = require('../../../lib/index.js'); assert.equal(math.det(3), 3); assert.equal(math.det([5]), 5); diff --git a/test/function/matrix/diag.test.js b/test/function/matrix/diag.test.js index e037c2f43..037680de9 100644 --- a/test/function/matrix/diag.test.js +++ b/test/function/matrix/diag.test.js @@ -1,5 +1,5 @@ var assert = require('assert'); -var math = require('../../../src/index.js'); +var math = require('../../../lib/index.js'); // test diag assert.deepEqual(math.diag([1,2,3]).valueOf(), [[1,0,0],[0,2,0],[0,0,3]]); diff --git a/test/function/matrix/eye.test.js b/test/function/matrix/eye.test.js index cb57810ef..ba2aaeb73 100644 --- a/test/function/matrix/eye.test.js +++ b/test/function/matrix/eye.test.js @@ -1,6 +1,6 @@ // test eye var assert = require('assert'); -var math = require('../../../src/index.js'); +var math = require('../../../lib/index.js'); assert.deepEqual(math.eye().valueOf(), [[1]]); assert.deepEqual(math.eye([]).valueOf(), [[1]]); diff --git a/test/function/matrix/inv.test.js b/test/function/matrix/inv.test.js index d46540abf..0359da3c5 100644 --- a/test/function/matrix/inv.test.js +++ b/test/function/matrix/inv.test.js @@ -1,6 +1,6 @@ // test inv var assert = require('assert'); -var math = require('../../../src/index.js'); +var math = require('../../../lib/index.js'); assert.deepEqual(math.inv(4), 1/4); assert.deepEqual(math.inv([4]), [1/4]); diff --git a/test/function/matrix/ones.test.js b/test/function/matrix/ones.test.js index 521c5824b..726c95671 100644 --- a/test/function/matrix/ones.test.js +++ b/test/function/matrix/ones.test.js @@ -1,6 +1,6 @@ // test ones var assert = require('assert'); -var math = require('../../../src/index.js'), +var math = require('../../../lib/index.js'), ones = math.ones; describe('ones', function() { diff --git a/test/function/matrix/size.test.js b/test/function/matrix/size.test.js index 2981fb25a..d1ab84d2b 100644 --- a/test/function/matrix/size.test.js +++ b/test/function/matrix/size.test.js @@ -1,6 +1,6 @@ // test size var assert = require('assert'); -var math = require('../../../src/index.js'); +var math = require('../../../lib/index.js'); describe('size', function() { diff --git a/test/function/matrix/squeeze.test.js b/test/function/matrix/squeeze.test.js index 5f1f54a70..8e8a04a6a 100644 --- a/test/function/matrix/squeeze.test.js +++ b/test/function/matrix/squeeze.test.js @@ -1,6 +1,6 @@ // test squeeze var assert = require('assert'); -var math = require('../../../src/index.js'), +var math = require('../../../lib/index.js'), squeeze = math.squeeze, size = math.size, matrix = math.matrix; diff --git a/test/function/matrix/subset.test.js b/test/function/matrix/subset.test.js index 9a2fa2ca4..b329d8fd5 100644 --- a/test/function/matrix/subset.test.js +++ b/test/function/matrix/subset.test.js @@ -1,6 +1,6 @@ // test subset var assert = require('assert'), - math = require('../../../src/index.js'), + math = require('../../../lib/index.js'), subset = math.subset, matrix = math.matrix, range = math.range; diff --git a/test/function/matrix/transpose.test.js b/test/function/matrix/transpose.test.js index a3a54ad97..f4e85d3ed 100644 --- a/test/function/matrix/transpose.test.js +++ b/test/function/matrix/transpose.test.js @@ -1,6 +1,6 @@ // test transpose var assert = require('assert'); -var math = require('../../../src/index.js'); +var math = require('../../../lib/index.js'); describe('transpose', function() { diff --git a/test/function/matrix/zeros.test.js b/test/function/matrix/zeros.test.js index 30ffc8718..f608b322d 100644 --- a/test/function/matrix/zeros.test.js +++ b/test/function/matrix/zeros.test.js @@ -1,6 +1,6 @@ // test zeros var assert = require('assert'); -var math = require('../../../src/index.js'), +var math = require('../../../lib/index.js'), zeros = math.zeros; describe('zeros', function() { diff --git a/test/function/probability/factorial.test.js b/test/function/probability/factorial.test.js index a4d9b3771..52db77fa1 100644 --- a/test/function/probability/factorial.test.js +++ b/test/function/probability/factorial.test.js @@ -1,6 +1,6 @@ // test factorial var assert = require('assert'); -var math = require('../../../src/index.js'); +var math = require('../../../lib/index.js'); assert.equal(math.factorial(0), 1); assert.equal(math.factorial(1), 1); diff --git a/test/function/probability/random.test.js b/test/function/probability/random.test.js index c992f9c20..470a9d3a0 100644 --- a/test/function/probability/random.test.js +++ b/test/function/probability/random.test.js @@ -1,6 +1,6 @@ var assert = require('assert'), _ = require('underscore'), - math = require('../../../src/index.js'); + math = require('../../../lib/index.js'); var assertApproxEqual = function(testVal, val, tolerance) { var diff = Math.abs(val - testVal); diff --git a/test/function/statistics/max.test.js b/test/function/statistics/max.test.js index bb37f4795..904914fb3 100644 --- a/test/function/statistics/max.test.js +++ b/test/function/statistics/max.test.js @@ -1,6 +1,6 @@ // test max var assert = require('assert'); -var math = require('../../../src/index.js'); +var math = require('../../../lib/index.js'); assert.equal(math.max(5), 5); assert.equal(math.max(3,1), 3); diff --git a/test/function/statistics/min.test.js b/test/function/statistics/min.test.js index 1c3554a40..733a9c547 100644 --- a/test/function/statistics/min.test.js +++ b/test/function/statistics/min.test.js @@ -1,6 +1,6 @@ // test min var assert = require('assert'); -var math = require('../../../src/index.js'); +var math = require('../../../lib/index.js'); assert.equal(math.min(5), 5); assert.equal(math.min(1,3), 1); diff --git a/test/function/trigonometry/acos.test.js b/test/function/trigonometry/acos.test.js index cef9a2903..e96809256 100644 --- a/test/function/trigonometry/acos.test.js +++ b/test/function/trigonometry/acos.test.js @@ -1,6 +1,6 @@ // test acos var assert = require('assert'), - math = require('../../../src/index.js'), + math = require('../../../lib/index.js'), approx = require('../../../tools/approx.js'), pi = math.pi, acos = math.acos, diff --git a/test/function/trigonometry/asin.test.js b/test/function/trigonometry/asin.test.js index 61a1215be..f3c41198a 100644 --- a/test/function/trigonometry/asin.test.js +++ b/test/function/trigonometry/asin.test.js @@ -1,6 +1,6 @@ // test asin var assert = require('assert'), - math = require('../../../src/index.js'), + math = require('../../../lib/index.js'), approx = require('../../../tools/approx.js'), pi = math.pi, complex = math.complex, diff --git a/test/function/trigonometry/atan.test.js b/test/function/trigonometry/atan.test.js index 9178068e2..966b04783 100644 --- a/test/function/trigonometry/atan.test.js +++ b/test/function/trigonometry/atan.test.js @@ -1,6 +1,6 @@ // test atan var assert = require('assert'), - math = require('../../../src/index.js'), + math = require('../../../lib/index.js'), approx = require('../../../tools/approx.js'), pi = math.pi, complex = math.complex, diff --git a/test/function/trigonometry/atan2.test.js b/test/function/trigonometry/atan2.test.js index 9a151583a..af8b353e2 100644 --- a/test/function/trigonometry/atan2.test.js +++ b/test/function/trigonometry/atan2.test.js @@ -1,6 +1,6 @@ // test atan2 var assert = require('assert'), - math = require('../../../src/index.js'), + math = require('../../../lib/index.js'), approx = require('../../../tools/approx.js'), pi = math.pi, acos = math.acos, diff --git a/test/function/trigonometry/cos.test.js b/test/function/trigonometry/cos.test.js index 70d0ae4de..7aa30aefe 100644 --- a/test/function/trigonometry/cos.test.js +++ b/test/function/trigonometry/cos.test.js @@ -1,6 +1,6 @@ // test cos var assert = require('assert'), - math = require('../../../src/index.js'), + math = require('../../../lib/index.js'), approx = require('../../../tools/approx.js'), pi = math.pi, complex = math.complex, diff --git a/test/function/trigonometry/cot.test.js b/test/function/trigonometry/cot.test.js index 1931886b8..ed747b533 100644 --- a/test/function/trigonometry/cot.test.js +++ b/test/function/trigonometry/cot.test.js @@ -1,6 +1,6 @@ // test cot var assert = require('assert'), - math = require('../../../src/index.js'), + math = require('../../../lib/index.js'), approx = require('../../../tools/approx.js'), pi = math.pi, complex = math.complex, diff --git a/test/function/trigonometry/csc.test.js b/test/function/trigonometry/csc.test.js index 742f7b408..f21505d7a 100644 --- a/test/function/trigonometry/csc.test.js +++ b/test/function/trigonometry/csc.test.js @@ -1,6 +1,6 @@ // test csc var assert = require('assert'), - math = require('../../../src/index.js'), + math = require('../../../lib/index.js'), approx = require('../../../tools/approx.js'), pi = math.pi, complex = math.complex, diff --git a/test/function/trigonometry/sec.test.js b/test/function/trigonometry/sec.test.js index deb3ddb30..87bb15662 100644 --- a/test/function/trigonometry/sec.test.js +++ b/test/function/trigonometry/sec.test.js @@ -1,6 +1,6 @@ // test sec var assert = require('assert'), - math = require('../../../src/index.js'), + math = require('../../../lib/index.js'), approx = require('../../../tools/approx.js'), pi = math.pi, complex = math.complex, diff --git a/test/function/trigonometry/sin.test.js b/test/function/trigonometry/sin.test.js index 72580af55..8e58ca2ae 100644 --- a/test/function/trigonometry/sin.test.js +++ b/test/function/trigonometry/sin.test.js @@ -1,6 +1,6 @@ // test sin var assert = require('assert'), - math = require('../../../src/index.js'), + math = require('../../../lib/index.js'), approx = require('../../../tools/approx.js'), pi = math.pi, complex = math.complex, diff --git a/test/function/trigonometry/tan.test.js b/test/function/trigonometry/tan.test.js index 49fa964fe..aaa042bb1 100644 --- a/test/function/trigonometry/tan.test.js +++ b/test/function/trigonometry/tan.test.js @@ -1,6 +1,6 @@ // test tan var assert = require('assert'), - math = require('../../../src/index.js'), + math = require('../../../lib/index.js'), approx = require('../../../tools/approx.js'), pi = math.pi, complex = math.complex, diff --git a/test/function/units/in.test.js b/test/function/units/in.test.js index f7276359c..398480fbc 100644 --- a/test/function/units/in.test.js +++ b/test/function/units/in.test.js @@ -2,7 +2,7 @@ var assert = require('assert'), approx = require('../../../tools/approx.js'), - math = require('../../../src/index.js'), + math = require('../../../lib/index.js'), unit = math.unit; // test function in diff --git a/test/function/utils/clone.test.js b/test/function/utils/clone.test.js index 8a3e72a52..a23c0b1a9 100644 --- a/test/function/utils/clone.test.js +++ b/test/function/utils/clone.test.js @@ -1,6 +1,6 @@ // test clone var assert = require('assert'); -var math = require('../../../src/index.js'); +var math = require('../../../lib/index.js'); var a = 1; var b = math.clone(a); diff --git a/test/function/utils/eval.test.js b/test/function/utils/eval.test.js index d5006c6a3..2270d2196 100644 --- a/test/function/utils/eval.test.js +++ b/test/function/utils/eval.test.js @@ -1,6 +1,6 @@ // test eval var assert = require('assert'); -var math = require('../../../src/index.js'); +var math = require('../../../lib/index.js'); // test some expressions assert.equal(math.eval('pi'), Math.PI); diff --git a/test/function/utils/format.test.js b/test/function/utils/format.test.js index b790205f3..15abedd73 100644 --- a/test/function/utils/format.test.js +++ b/test/function/utils/format.test.js @@ -1,6 +1,6 @@ // test format var assert = require('assert'); -var math = require('../../../src/index.js'); +var math = require('../../../lib/index.js'); assert.equal(math.format(2/7), '0.28571'); assert.equal(math.format(0.10400), '0.104'); diff --git a/test/function/utils/help.test.js b/test/function/utils/help.test.js index e4eb5e42e..5c695a106 100644 --- a/test/function/utils/help.test.js +++ b/test/function/utils/help.test.js @@ -1,6 +1,6 @@ // test help var assert = require('assert'); -var math = require('../../../src/index.js'); +var math = require('../../../lib/index.js'); var prop; var help = math.help('sin'); diff --git a/test/function/utils/import.test.js b/test/function/utils/import.test.js index 8a5a1f8d0..3ff61a1dc 100644 --- a/test/function/utils/import.test.js +++ b/test/function/utils/import.test.js @@ -1,6 +1,6 @@ // test import var assert = require('assert'), - math = require('../../../src/index.js'), + math = require('../../../lib/index.js'), approx = require('../../../tools/approx.js'); math.import({ diff --git a/test/function/utils/parse.test.js b/test/function/utils/parse.test.js index 982782d11..65b3ea962 100644 --- a/test/function/utils/parse.test.js +++ b/test/function/utils/parse.test.js @@ -1,6 +1,6 @@ // test parse var assert = require('assert'); -var math = require('../../../src/index.js'); +var math = require('../../../lib/index.js'); // test some expressions assert.ok(math.parse('pi') instanceof math.expr.node.Node); diff --git a/test/function/utils/select.test.js b/test/function/utils/select.test.js index 686ec911b..96c66c9c0 100644 --- a/test/function/utils/select.test.js +++ b/test/function/utils/select.test.js @@ -1,7 +1,7 @@ // test select (chaining of operations) var assert = require('assert'), approx = require('../../../tools/approx.js'), - math = require('../../../src/index.js'); + math = require('../../../lib/index.js'); assert.ok(math.select(45) instanceof math.expr.Selector); assert.equal(math.select(3).add(4).subtract(2).done(), 5); diff --git a/test/function/utils/typeof.test.js b/test/function/utils/typeof.test.js index 579a6cd43..f4204ef9f 100644 --- a/test/function/utils/typeof.test.js +++ b/test/function/utils/typeof.test.js @@ -1,6 +1,6 @@ // test typeof var assert = require('assert'); -var math = require('../../../src/index.js'); +var math = require('../../../lib/index.js'); assert.equal(math.typeof(2), 'number'); assert.equal(math.typeof(new Number(2)), 'number'); diff --git a/test/type/complex.test.js b/test/type/complex.test.js index 280d0238a..3775e35c5 100644 --- a/test/type/complex.test.js +++ b/test/type/complex.test.js @@ -1,7 +1,7 @@ // test data type Complex var assert = require('assert'); -var math = require('../../src/index.js'); +var math = require('../../lib/index.js'); describe('Complex', function () { diff --git a/test/type/help.test.js b/test/type/help.test.js index 34b777ac6..b36b1584e 100644 --- a/test/type/help.test.js +++ b/test/type/help.test.js @@ -1,6 +1,6 @@ // test Help var assert = require('assert'); -var math = require('../../src/index.js'); +var math = require('../../lib/index.js'); var help = new math.type.Help(math, math.docs.sin); diff --git a/test/type/matrix.test.js b/test/type/matrix.test.js index d67f16039..33fd58966 100644 --- a/test/type/matrix.test.js +++ b/test/type/matrix.test.js @@ -1,7 +1,7 @@ // test data type Matrix var assert = require('assert'); -var math = require('../../src/index.js'); +var math = require('../../lib/index.js'); var m = math.matrix(); assert.equal(m.isScalar(), true); diff --git a/test/type/range.test.js b/test/type/range.test.js index e15da10d3..dee1c23b7 100644 --- a/test/type/range.test.js +++ b/test/type/range.test.js @@ -1,7 +1,7 @@ // test data type Range var assert = require('assert'); -var math = require('../../src/index.js'); +var math = require('../../lib/index.js'); var r = math.range(2,6); assert.deepEqual(r.toArray(), [2,3,4,5]); diff --git a/test/type/unit.test.js b/test/type/unit.test.js index 8a70dfcb3..0ccc1d9c1 100644 --- a/test/type/unit.test.js +++ b/test/type/unit.test.js @@ -1,7 +1,7 @@ // test data type Unit var assert = require('assert'); -var math = require('../../src/index.js'); +var math = require('../../lib/index.js'); var unit1 = math.unit(5000, 'cm'); diff --git a/test/util/array.test.js b/test/util/array.test.js index 86170a583..0439389df 100644 --- a/test/util/array.test.js +++ b/test/util/array.test.js @@ -1,5 +1,5 @@ var assert = require('assert'), - array = require('../../src/util/array.js'), + array = require('../../lib/util/array.js'), resize = array.resize; size = array.size; diff --git a/tools/jake-utils.js b/tools/jake-utils.js index ac30eb979..71a125fd9 100644 --- a/tools/jake-utils.js +++ b/tools/jake-utils.js @@ -133,9 +133,9 @@ function replace (params) { * Example: * var result = concat({ * src: [ - * './src/main.js', - * './src/extra.js', - * './src/functions/**', + * './lib/main.js', + * './lib/extra.js', + * './lib/functions/**', * ], * dest: './lib/mylibrary.js', // optional * header: '// license information...', // optional From a59526634703c6b2a7bd51c089391ad7d6d37394 Mon Sep 17 00:00:00 2001 From: Sebastien Piquemal Date: Wed, 14 Aug 2013 15:39:21 +0400 Subject: [PATCH 2/4] added all files in lib/ --- lib/constants.js | 23 + lib/docs/constants/Infinity.js | 13 + lib/docs/constants/LN10.js | 13 + lib/docs/constants/LN2.js | 13 + lib/docs/constants/LOG10E.js | 13 + lib/docs/constants/LOG2E.js | 13 + lib/docs/constants/NaN.js | 13 + lib/docs/constants/SQRT1_2.js | 13 + lib/docs/constants/SQRT2.js | 13 + lib/docs/constants/e.js | 15 + lib/docs/constants/false.js | 12 + lib/docs/constants/i.js | 14 + lib/docs/constants/pi.js | 13 + lib/docs/constants/tau.js | 13 + lib/docs/constants/true.js | 12 + lib/docs/function/arithmetic/abs.js | 13 + lib/docs/function/arithmetic/add.js | 19 + lib/docs/function/arithmetic/ceil.js | 15 + lib/docs/function/arithmetic/cube.js | 18 + lib/docs/function/arithmetic/divide.js | 20 + lib/docs/function/arithmetic/edivide.js | 19 + lib/docs/function/arithmetic/emultiply.js | 19 + lib/docs/function/arithmetic/epow.js | 17 + lib/docs/function/arithmetic/equal.js | 21 + lib/docs/function/arithmetic/exp.js | 20 + lib/docs/function/arithmetic/fix.js | 16 + lib/docs/function/arithmetic/floor.js | 15 + lib/docs/function/arithmetic/gcd.js | 15 + lib/docs/function/arithmetic/larger.js | 22 + lib/docs/function/arithmetic/largereq.js | 20 + lib/docs/function/arithmetic/lcm.js | 14 + lib/docs/function/arithmetic/log.js | 23 + lib/docs/function/arithmetic/log10.js | 19 + lib/docs/function/arithmetic/mod.js | 20 + lib/docs/function/arithmetic/multiply.js | 19 + lib/docs/function/arithmetic/pow.js | 18 + lib/docs/function/arithmetic/round.js | 19 + lib/docs/function/arithmetic/sign.js | 17 + lib/docs/function/arithmetic/smaller.js | 21 + lib/docs/function/arithmetic/smallereq.js | 20 + lib/docs/function/arithmetic/sqrt.js | 18 + lib/docs/function/arithmetic/square.js | 21 + lib/docs/function/arithmetic/subtract.js | 19 + lib/docs/function/arithmetic/unary.js | 17 + lib/docs/function/arithmetic/unequal.js | 22 + lib/docs/function/arithmetic/xgcd.js | 14 + lib/docs/function/complex/arg.js | 20 + lib/docs/function/complex/conj.js | 20 + lib/docs/function/complex/im.js | 20 + lib/docs/function/complex/re.js | 20 + lib/docs/function/construction/boolean.js | 20 + lib/docs/function/construction/complex.js | 19 + lib/docs/function/construction/matrix.js | 22 + lib/docs/function/construction/number.js | 21 + lib/docs/function/construction/range.js | 25 + lib/docs/function/construction/string.js | 18 + lib/docs/function/construction/unit.js | 20 + lib/docs/function/matrix/concat.js | 20 + lib/docs/function/matrix/det.js | 15 + lib/docs/function/matrix/diag.js | 18 + lib/docs/function/matrix/eye.js | 20 + lib/docs/function/matrix/inv.js | 16 + lib/docs/function/matrix/ones.js | 23 + lib/docs/function/matrix/size.js | 18 + lib/docs/function/matrix/squeeze.js | 17 + lib/docs/function/matrix/subset.js | 23 + lib/docs/function/matrix/transpose.js | 17 + lib/docs/function/matrix/zeros.js | 22 + lib/docs/function/probability/factorial.js | 15 + lib/docs/function/probability/random.js | 13 + lib/docs/function/probability/randomInt.js | 13 + lib/docs/function/statistics/max.js | 22 + lib/docs/function/statistics/min.js | 22 + lib/docs/function/trigonometry/acos.js | 17 + lib/docs/function/trigonometry/asin.js | 17 + lib/docs/function/trigonometry/atan.js | 17 + lib/docs/function/trigonometry/atan2.js | 21 + lib/docs/function/trigonometry/cos.js | 20 + lib/docs/function/trigonometry/cot.js | 17 + lib/docs/function/trigonometry/csc.js | 17 + lib/docs/function/trigonometry/sec.js | 17 + lib/docs/function/trigonometry/sin.js | 20 + lib/docs/function/trigonometry/tan.js | 19 + lib/docs/function/units/in.js | 15 + lib/docs/function/utils/clone.js | 16 + lib/docs/function/utils/eval.js | 14 + lib/docs/function/utils/format.js | 14 + lib/docs/function/utils/help.js | 14 + lib/docs/function/utils/import.js | 13 + lib/docs/function/utils/typeof.js | 15 + lib/docs/index.js | 110 ++ lib/exports.js | 30 + lib/expr/Parser.js | 122 ++ lib/expr/Scope.js | 187 +++ lib/expr/Selector.js | 129 ++ lib/expr/node/AssignmentNode.js | 63 + lib/expr/node/BlockNode.js | 85 ++ lib/expr/node/ConstantNode.js | 31 + lib/expr/node/FunctionNode.js | 87 ++ lib/expr/node/MatrixNode.js | 155 +++ lib/expr/node/Node.js | 71 ++ lib/expr/node/OperatorNode.js | 86 ++ lib/expr/node/ParamsNode.js | 129 ++ lib/expr/node/SymbolNode.js | 42 + lib/expr/node/UpdateNode.js | 137 ++ lib/expr/node/handlers.js | 4 + lib/expr/node/index.js | 12 + lib/function/arithmetic/abs.js | 46 + lib/function/arithmetic/add.js | 97 ++ lib/function/arithmetic/ceil.js | 48 + lib/function/arithmetic/cube.js | 46 + lib/function/arithmetic/divide.js | 109 ++ lib/function/arithmetic/edivide.js | 22 + lib/function/arithmetic/emultiply.js | 22 + lib/function/arithmetic/epow.js | 22 + lib/function/arithmetic/equal.js | 71 ++ lib/function/arithmetic/exp.js | 49 + lib/function/arithmetic/fix.js | 48 + lib/function/arithmetic/floor.js | 48 + lib/function/arithmetic/gcd.js | 66 + lib/function/arithmetic/larger.js | 71 ++ lib/function/arithmetic/largereq.js | 71 ++ lib/function/arithmetic/lcm.js | 71 ++ lib/function/arithmetic/log.js | 63 + lib/function/arithmetic/log10.js | 54 + lib/function/arithmetic/mod.js | 74 ++ lib/function/arithmetic/multiply.js | 210 +++ lib/function/arithmetic/pow.js | 105 ++ lib/function/arithmetic/round.js | 104 ++ lib/function/arithmetic/sign.js | 48 + lib/function/arithmetic/smaller.js | 71 ++ lib/function/arithmetic/smallereq.js | 71 ++ lib/function/arithmetic/sqrt.js | 62 + lib/function/arithmetic/square.js | 46 + lib/function/arithmetic/subtract.js | 94 ++ lib/function/arithmetic/unary.js | 55 + lib/function/arithmetic/unequal.js | 66 + lib/function/arithmetic/xgcd.js | 45 + lib/function/complex/arg.js | 47 + lib/function/complex/conj.js | 48 + lib/function/complex/im.js | 46 + lib/function/complex/re.js | 47 + lib/function/construction/boolean.js | 48 + lib/function/construction/complex.js | 69 + lib/function/construction/matrix.js | 30 + lib/function/construction/number.js | 26 + lib/function/construction/parser.js | 45 + lib/function/construction/range.js | 73 ++ lib/function/construction/string.js | 56 + lib/function/construction/unit.js | 59 + lib/function/matrix/concat.js | 115 ++ lib/function/matrix/det.js | 143 +++ lib/function/matrix/diag.js | 87 ++ lib/function/matrix/eye.js | 58 + lib/function/matrix/inv.js | 185 +++ lib/function/matrix/ones.js | 36 + lib/function/matrix/size.js | 50 + lib/function/matrix/squeeze.js | 59 + lib/function/matrix/subset.js | 205 +++ lib/function/matrix/transpose.js | 68 + lib/function/matrix/zeros.js | 36 + lib/function/probability/factorial.js | 58 + lib/function/probability/random.js | 166 +++ lib/function/statistics/max.js | 103 ++ lib/function/statistics/min.js | 103 ++ lib/function/trigonometry/acos.js | 85 ++ lib/function/trigonometry/asin.js | 82 ++ lib/function/trigonometry/atan.js | 69 + lib/function/trigonometry/atan2.js | 61 + lib/function/trigonometry/cos.js | 60 + lib/function/trigonometry/cot.js | 60 + lib/function/trigonometry/csc.js | 61 + lib/function/trigonometry/sec.js | 60 + lib/function/trigonometry/sin.js | 59 + lib/function/trigonometry/tan.js | 63 + lib/function/units/in.js | 47 + lib/function/utils/clone.js | 20 + lib/function/utils/eval.js | 72 ++ lib/function/utils/format.js | 32 + lib/function/utils/help.js | 58 + lib/function/utils/import.js | 120 ++ lib/function/utils/parse.js | 1334 ++++++++++++++++++++ lib/function/utils/select.js | 40 + lib/function/utils/typeof.js | 20 + lib/header.js | 26 + lib/options.js | 2 + lib/shim.js | 183 +++ lib/type/Complex.js | 367 ++++++ lib/type/Help.js | 92 ++ lib/type/Matrix.js | 680 ++++++++++ lib/type/Range.js | 255 ++++ lib/type/Unit.js | 725 +++++++++++ lib/type/collection.js | 228 ++++ lib/type/index.js | 7 + lib/util/array.js | 221 ++++ lib/util/boolean.js | 8 + lib/util/error.js | 47 + lib/util/index.js | 7 + lib/util/number.js | 87 ++ lib/util/object.js | 131 ++ lib/util/string.js | 150 +++ lib/util/types.js | 66 + 202 files changed, 12884 insertions(+) create mode 100644 lib/constants.js create mode 100644 lib/docs/constants/Infinity.js create mode 100644 lib/docs/constants/LN10.js create mode 100644 lib/docs/constants/LN2.js create mode 100644 lib/docs/constants/LOG10E.js create mode 100644 lib/docs/constants/LOG2E.js create mode 100644 lib/docs/constants/NaN.js create mode 100644 lib/docs/constants/SQRT1_2.js create mode 100644 lib/docs/constants/SQRT2.js create mode 100644 lib/docs/constants/e.js create mode 100644 lib/docs/constants/false.js create mode 100644 lib/docs/constants/i.js create mode 100644 lib/docs/constants/pi.js create mode 100644 lib/docs/constants/tau.js create mode 100644 lib/docs/constants/true.js create mode 100644 lib/docs/function/arithmetic/abs.js create mode 100644 lib/docs/function/arithmetic/add.js create mode 100644 lib/docs/function/arithmetic/ceil.js create mode 100644 lib/docs/function/arithmetic/cube.js create mode 100644 lib/docs/function/arithmetic/divide.js create mode 100644 lib/docs/function/arithmetic/edivide.js create mode 100644 lib/docs/function/arithmetic/emultiply.js create mode 100644 lib/docs/function/arithmetic/epow.js create mode 100644 lib/docs/function/arithmetic/equal.js create mode 100644 lib/docs/function/arithmetic/exp.js create mode 100644 lib/docs/function/arithmetic/fix.js create mode 100644 lib/docs/function/arithmetic/floor.js create mode 100644 lib/docs/function/arithmetic/gcd.js create mode 100644 lib/docs/function/arithmetic/larger.js create mode 100644 lib/docs/function/arithmetic/largereq.js create mode 100644 lib/docs/function/arithmetic/lcm.js create mode 100644 lib/docs/function/arithmetic/log.js create mode 100644 lib/docs/function/arithmetic/log10.js create mode 100644 lib/docs/function/arithmetic/mod.js create mode 100644 lib/docs/function/arithmetic/multiply.js create mode 100644 lib/docs/function/arithmetic/pow.js create mode 100644 lib/docs/function/arithmetic/round.js create mode 100644 lib/docs/function/arithmetic/sign.js create mode 100644 lib/docs/function/arithmetic/smaller.js create mode 100644 lib/docs/function/arithmetic/smallereq.js create mode 100644 lib/docs/function/arithmetic/sqrt.js create mode 100644 lib/docs/function/arithmetic/square.js create mode 100644 lib/docs/function/arithmetic/subtract.js create mode 100644 lib/docs/function/arithmetic/unary.js create mode 100644 lib/docs/function/arithmetic/unequal.js create mode 100644 lib/docs/function/arithmetic/xgcd.js create mode 100644 lib/docs/function/complex/arg.js create mode 100644 lib/docs/function/complex/conj.js create mode 100644 lib/docs/function/complex/im.js create mode 100644 lib/docs/function/complex/re.js create mode 100644 lib/docs/function/construction/boolean.js create mode 100644 lib/docs/function/construction/complex.js create mode 100644 lib/docs/function/construction/matrix.js create mode 100644 lib/docs/function/construction/number.js create mode 100644 lib/docs/function/construction/range.js create mode 100644 lib/docs/function/construction/string.js create mode 100644 lib/docs/function/construction/unit.js create mode 100644 lib/docs/function/matrix/concat.js create mode 100644 lib/docs/function/matrix/det.js create mode 100644 lib/docs/function/matrix/diag.js create mode 100644 lib/docs/function/matrix/eye.js create mode 100644 lib/docs/function/matrix/inv.js create mode 100644 lib/docs/function/matrix/ones.js create mode 100644 lib/docs/function/matrix/size.js create mode 100644 lib/docs/function/matrix/squeeze.js create mode 100644 lib/docs/function/matrix/subset.js create mode 100644 lib/docs/function/matrix/transpose.js create mode 100644 lib/docs/function/matrix/zeros.js create mode 100644 lib/docs/function/probability/factorial.js create mode 100644 lib/docs/function/probability/random.js create mode 100644 lib/docs/function/probability/randomInt.js create mode 100644 lib/docs/function/statistics/max.js create mode 100644 lib/docs/function/statistics/min.js create mode 100644 lib/docs/function/trigonometry/acos.js create mode 100644 lib/docs/function/trigonometry/asin.js create mode 100644 lib/docs/function/trigonometry/atan.js create mode 100644 lib/docs/function/trigonometry/atan2.js create mode 100644 lib/docs/function/trigonometry/cos.js create mode 100644 lib/docs/function/trigonometry/cot.js create mode 100644 lib/docs/function/trigonometry/csc.js create mode 100644 lib/docs/function/trigonometry/sec.js create mode 100644 lib/docs/function/trigonometry/sin.js create mode 100644 lib/docs/function/trigonometry/tan.js create mode 100644 lib/docs/function/units/in.js create mode 100644 lib/docs/function/utils/clone.js create mode 100644 lib/docs/function/utils/eval.js create mode 100644 lib/docs/function/utils/format.js create mode 100644 lib/docs/function/utils/help.js create mode 100644 lib/docs/function/utils/import.js create mode 100644 lib/docs/function/utils/typeof.js create mode 100644 lib/docs/index.js create mode 100644 lib/exports.js create mode 100644 lib/expr/Parser.js create mode 100644 lib/expr/Scope.js create mode 100644 lib/expr/Selector.js create mode 100644 lib/expr/node/AssignmentNode.js create mode 100644 lib/expr/node/BlockNode.js create mode 100644 lib/expr/node/ConstantNode.js create mode 100644 lib/expr/node/FunctionNode.js create mode 100644 lib/expr/node/MatrixNode.js create mode 100644 lib/expr/node/Node.js create mode 100644 lib/expr/node/OperatorNode.js create mode 100644 lib/expr/node/ParamsNode.js create mode 100644 lib/expr/node/SymbolNode.js create mode 100644 lib/expr/node/UpdateNode.js create mode 100644 lib/expr/node/handlers.js create mode 100644 lib/expr/node/index.js create mode 100644 lib/function/arithmetic/abs.js create mode 100644 lib/function/arithmetic/add.js create mode 100644 lib/function/arithmetic/ceil.js create mode 100644 lib/function/arithmetic/cube.js create mode 100644 lib/function/arithmetic/divide.js create mode 100644 lib/function/arithmetic/edivide.js create mode 100644 lib/function/arithmetic/emultiply.js create mode 100644 lib/function/arithmetic/epow.js create mode 100644 lib/function/arithmetic/equal.js create mode 100644 lib/function/arithmetic/exp.js create mode 100644 lib/function/arithmetic/fix.js create mode 100644 lib/function/arithmetic/floor.js create mode 100644 lib/function/arithmetic/gcd.js create mode 100644 lib/function/arithmetic/larger.js create mode 100644 lib/function/arithmetic/largereq.js create mode 100644 lib/function/arithmetic/lcm.js create mode 100644 lib/function/arithmetic/log.js create mode 100644 lib/function/arithmetic/log10.js create mode 100644 lib/function/arithmetic/mod.js create mode 100644 lib/function/arithmetic/multiply.js create mode 100644 lib/function/arithmetic/pow.js create mode 100644 lib/function/arithmetic/round.js create mode 100644 lib/function/arithmetic/sign.js create mode 100644 lib/function/arithmetic/smaller.js create mode 100644 lib/function/arithmetic/smallereq.js create mode 100644 lib/function/arithmetic/sqrt.js create mode 100644 lib/function/arithmetic/square.js create mode 100644 lib/function/arithmetic/subtract.js create mode 100644 lib/function/arithmetic/unary.js create mode 100644 lib/function/arithmetic/unequal.js create mode 100644 lib/function/arithmetic/xgcd.js create mode 100644 lib/function/complex/arg.js create mode 100644 lib/function/complex/conj.js create mode 100644 lib/function/complex/im.js create mode 100644 lib/function/complex/re.js create mode 100644 lib/function/construction/boolean.js create mode 100644 lib/function/construction/complex.js create mode 100644 lib/function/construction/matrix.js create mode 100644 lib/function/construction/number.js create mode 100644 lib/function/construction/parser.js create mode 100644 lib/function/construction/range.js create mode 100644 lib/function/construction/string.js create mode 100644 lib/function/construction/unit.js create mode 100644 lib/function/matrix/concat.js create mode 100644 lib/function/matrix/det.js create mode 100644 lib/function/matrix/diag.js create mode 100644 lib/function/matrix/eye.js create mode 100644 lib/function/matrix/inv.js create mode 100644 lib/function/matrix/ones.js create mode 100644 lib/function/matrix/size.js create mode 100644 lib/function/matrix/squeeze.js create mode 100644 lib/function/matrix/subset.js create mode 100644 lib/function/matrix/transpose.js create mode 100644 lib/function/matrix/zeros.js create mode 100644 lib/function/probability/factorial.js create mode 100644 lib/function/probability/random.js create mode 100644 lib/function/statistics/max.js create mode 100644 lib/function/statistics/min.js create mode 100644 lib/function/trigonometry/acos.js create mode 100644 lib/function/trigonometry/asin.js create mode 100644 lib/function/trigonometry/atan.js create mode 100644 lib/function/trigonometry/atan2.js create mode 100644 lib/function/trigonometry/cos.js create mode 100644 lib/function/trigonometry/cot.js create mode 100644 lib/function/trigonometry/csc.js create mode 100644 lib/function/trigonometry/sec.js create mode 100644 lib/function/trigonometry/sin.js create mode 100644 lib/function/trigonometry/tan.js create mode 100644 lib/function/units/in.js create mode 100644 lib/function/utils/clone.js create mode 100644 lib/function/utils/eval.js create mode 100644 lib/function/utils/format.js create mode 100644 lib/function/utils/help.js create mode 100644 lib/function/utils/import.js create mode 100644 lib/function/utils/parse.js create mode 100644 lib/function/utils/select.js create mode 100644 lib/function/utils/typeof.js create mode 100644 lib/header.js create mode 100644 lib/options.js create mode 100644 lib/shim.js create mode 100644 lib/type/Complex.js create mode 100644 lib/type/Help.js create mode 100644 lib/type/Matrix.js create mode 100644 lib/type/Range.js create mode 100644 lib/type/Unit.js create mode 100644 lib/type/collection.js create mode 100644 lib/type/index.js create mode 100644 lib/util/array.js create mode 100644 lib/util/boolean.js create mode 100644 lib/util/error.js create mode 100644 lib/util/index.js create mode 100644 lib/util/number.js create mode 100644 lib/util/object.js create mode 100644 lib/util/string.js create mode 100644 lib/util/types.js diff --git a/lib/constants.js b/lib/constants.js new file mode 100644 index 000000000..21f77137a --- /dev/null +++ b/lib/constants.js @@ -0,0 +1,23 @@ +module.exports = function (math) { + var Complex = require('./type/Complex.js'); + + math.pi = Math.PI; + math.e = Math.E; + math.tau = Math.PI * 2; + math.i = new Complex(0, 1); + + math['Infinity'] = Infinity; + math['NaN'] = NaN; + math['true'] = true; + math['false'] = false; + + // uppercase constants (for compatibility with built-in Math) + math.E = Math.E; + math.LN2 = Math.LN2; + math.LN10 = Math.LN10; + math.LOG2E = Math.LOG2E; + math.LOG10E = Math.LOG10E; + math.PI = Math.PI; + math.SQRT1_2 = Math.SQRT1_2; + math.SQRT2 = Math.SQRT2; +}; diff --git a/lib/docs/constants/Infinity.js b/lib/docs/constants/Infinity.js new file mode 100644 index 000000000..181ae1693 --- /dev/null +++ b/lib/docs/constants/Infinity.js @@ -0,0 +1,13 @@ +module.exports = { + 'name': 'Infinity', + 'category': 'Constants', + 'syntax': [ + 'Infinity' + ], + 'description': 'Infinity, a number which is larger than the maximum number that can be handled by a floating point number.', + 'examples': [ + 'Infinity', + '1 / 0' + ], + 'seealso': [] +}; diff --git a/lib/docs/constants/LN10.js b/lib/docs/constants/LN10.js new file mode 100644 index 000000000..f9bad91a0 --- /dev/null +++ b/lib/docs/constants/LN10.js @@ -0,0 +1,13 @@ +module.exports = { + 'name': 'LN10', + 'category': 'Constants', + 'syntax': [ + 'LN10' + ], + 'description': 'Returns the natural logarithm of 10, approximately equal to 2.302', + 'examples': [ + 'LN10', + 'log(10)' + ], + 'seealso': [] +}; diff --git a/lib/docs/constants/LN2.js b/lib/docs/constants/LN2.js new file mode 100644 index 000000000..fad9b55c2 --- /dev/null +++ b/lib/docs/constants/LN2.js @@ -0,0 +1,13 @@ +module.exports = { + 'name': 'LN2', + 'category': 'Constants', + 'syntax': [ + 'LN2' + ], + 'description': 'Returns the natural logarithm of 2, approximately equal to 0.693', + 'examples': [ + 'LN2', + 'log(2)' + ], + 'seealso': [] +}; diff --git a/lib/docs/constants/LOG10E.js b/lib/docs/constants/LOG10E.js new file mode 100644 index 000000000..2b8c7da2c --- /dev/null +++ b/lib/docs/constants/LOG10E.js @@ -0,0 +1,13 @@ +module.exports = { + 'name': 'LOG10E', + 'category': 'Constants', + 'syntax': [ + 'LOG10E' + ], + 'description': 'Returns the base-10 logarithm of E, approximately equal to 0.434', + 'examples': [ + 'LOG10E', + 'log(e, 10)' + ], + 'seealso': [] +}; diff --git a/lib/docs/constants/LOG2E.js b/lib/docs/constants/LOG2E.js new file mode 100644 index 000000000..ebd1fa1b1 --- /dev/null +++ b/lib/docs/constants/LOG2E.js @@ -0,0 +1,13 @@ +module.exports = { + 'name': 'LOG2E', + 'category': 'Constants', + 'syntax': [ + 'LOG2E' + ], + 'description': 'Returns the base-2 logarithm of E, approximately equal to 1.442', + 'examples': [ + 'LOG2E', + 'log(e, 2)' + ], + 'seealso': [] +}; diff --git a/lib/docs/constants/NaN.js b/lib/docs/constants/NaN.js new file mode 100644 index 000000000..afcf76a2d --- /dev/null +++ b/lib/docs/constants/NaN.js @@ -0,0 +1,13 @@ +module.exports = { + 'name': 'NaN', + 'category': 'Constants', + 'syntax': [ + 'NaN' + ], + 'description': 'Not a number', + 'examples': [ + 'NaN', + '0 / 0' + ], + 'seealso': [] +}; diff --git a/lib/docs/constants/SQRT1_2.js b/lib/docs/constants/SQRT1_2.js new file mode 100644 index 000000000..0ed86aaef --- /dev/null +++ b/lib/docs/constants/SQRT1_2.js @@ -0,0 +1,13 @@ +module.exports = { + 'name': 'SQRT1_2', + 'category': 'Constants', + 'syntax': [ + 'SQRT1_2' + ], + 'description': 'Returns the square root of 1/2, approximately equal to 0.707', + 'examples': [ + 'SQRT1_2', + 'sqrt(1/2)' + ], + 'seealso': [] +}; diff --git a/lib/docs/constants/SQRT2.js b/lib/docs/constants/SQRT2.js new file mode 100644 index 000000000..d89d4c3c4 --- /dev/null +++ b/lib/docs/constants/SQRT2.js @@ -0,0 +1,13 @@ +module.exports = { + 'name': 'SQRT2', + 'category': 'Constants', + 'syntax': [ + 'SQRT2' + ], + 'description': 'Returns the square root of 2, approximately equal to 1.414', + 'examples': [ + 'SQRT2', + 'sqrt(2)' + ], + 'seealso': [] +}; diff --git a/lib/docs/constants/e.js b/lib/docs/constants/e.js new file mode 100644 index 000000000..c12df5319 --- /dev/null +++ b/lib/docs/constants/e.js @@ -0,0 +1,15 @@ +module.exports = { + 'name': 'e', + 'category': 'Constants', + 'syntax': [ + 'e' + ], + 'description': 'Euler\'s number, the base of the natural logarithm. Approximately equal to 2.71828', + 'examples': [ + 'e', + 'e ^ 2', + 'exp(2)', + 'log(e)' + ], + 'seealso': ['exp'] +}; diff --git a/lib/docs/constants/false.js b/lib/docs/constants/false.js new file mode 100644 index 000000000..851084e6e --- /dev/null +++ b/lib/docs/constants/false.js @@ -0,0 +1,12 @@ +module.exports = { + 'name': 'false', + 'category': 'Constants', + 'syntax': [ + 'false' + ], + 'description': 'Boolean value false', + 'examples': [ + 'false' + ], + 'seealso': ['true'] +}; diff --git a/lib/docs/constants/i.js b/lib/docs/constants/i.js new file mode 100644 index 000000000..ae340203a --- /dev/null +++ b/lib/docs/constants/i.js @@ -0,0 +1,14 @@ +module.exports = { + 'name': 'i', + 'category': 'Constants', + 'syntax': [ + 'i' + ], + 'description': 'Imaginary unit, defined as i*i=-1. A complex number is described as a + b*i, where a is the real part, and b is the imaginary part.', + 'examples': [ + 'i', + 'i * i', + 'sqrt(-1)' + ], + 'seealso': [] +}; diff --git a/lib/docs/constants/pi.js b/lib/docs/constants/pi.js new file mode 100644 index 000000000..ed7ea151d --- /dev/null +++ b/lib/docs/constants/pi.js @@ -0,0 +1,13 @@ +module.exports = { + 'name': 'pi', + 'category': 'Constants', + 'syntax': [ + 'pi' + ], + 'description': 'The number pi is a mathematical constant that is the ratio of a circle\'s circumference to its diameter, and is approximately equal to 3.14159', + 'examples': [ + 'pi', + 'sin(pi/2)' + ], + 'seealso': ['tau'] +}; diff --git a/lib/docs/constants/tau.js b/lib/docs/constants/tau.js new file mode 100644 index 000000000..76e3f254b --- /dev/null +++ b/lib/docs/constants/tau.js @@ -0,0 +1,13 @@ +module.exports = { + 'name': 'tau', + 'category': 'Constants', + 'syntax': [ + 'pi' + ], + 'description': 'Tau is the ratio constant of a circle\'s circumference to radius, equal to 2 * pi, approximately 6.2832.', + 'examples': [ + 'tau', + '2 * pi' + ], + 'seealso': ['pi'] +}; diff --git a/lib/docs/constants/true.js b/lib/docs/constants/true.js new file mode 100644 index 000000000..fce262c3a --- /dev/null +++ b/lib/docs/constants/true.js @@ -0,0 +1,12 @@ +module.exports = { + 'name': 'true', + 'category': 'Constants', + 'syntax': [ + 'true' + ], + 'description': 'Boolean value true', + 'examples': [ + 'true' + ], + 'seealso': ['false'] +}; diff --git a/lib/docs/function/arithmetic/abs.js b/lib/docs/function/arithmetic/abs.js new file mode 100644 index 000000000..4b5bf329b --- /dev/null +++ b/lib/docs/function/arithmetic/abs.js @@ -0,0 +1,13 @@ +module.exports = { + 'name': 'abs', + 'category': 'Arithmetic', + 'syntax': [ + 'abs(x)' + ], + 'description': 'Compute the absolute value.', + 'examples': [ + 'abs(3.5)', + 'abs(-4.2)' + ], + 'seealso': ['sign'] +}; diff --git a/lib/docs/function/arithmetic/add.js b/lib/docs/function/arithmetic/add.js new file mode 100644 index 000000000..0c4193c55 --- /dev/null +++ b/lib/docs/function/arithmetic/add.js @@ -0,0 +1,19 @@ +module.exports = { + 'name': 'add', + 'category': 'Operators', + 'syntax': [ + 'x + y', + 'add(x, y)' + ], + 'description': 'Add two values.', + 'examples': [ + '2.1 + 3.6', + 'ans - 3.6', + '3 + 2i', + '"hello" + " world"', + '3 cm + 2 inch' + ], + 'seealso': [ + 'subtract' + ] +}; diff --git a/lib/docs/function/arithmetic/ceil.js b/lib/docs/function/arithmetic/ceil.js new file mode 100644 index 000000000..1395437a0 --- /dev/null +++ b/lib/docs/function/arithmetic/ceil.js @@ -0,0 +1,15 @@ +module.exports = { + 'name': 'ceil', + 'category': 'Arithmetic', + 'syntax': [ + 'ceil(x)' + ], + 'description': + 'Round a value towards plus infinity.If x is complex, both real and imaginary part are rounded towards plus infinity.', + 'examples': [ + 'ceil(3.2)', + 'ceil(3.8)', + 'ceil(-4.2)' + ], + 'seealso': ['floor', 'fix', 'round'] +}; diff --git a/lib/docs/function/arithmetic/cube.js b/lib/docs/function/arithmetic/cube.js new file mode 100644 index 000000000..21c586678 --- /dev/null +++ b/lib/docs/function/arithmetic/cube.js @@ -0,0 +1,18 @@ +module.exports = { + 'name': 'cube', + 'category': 'Arithmetic', + 'syntax': [ + 'cube(x)' + ], + 'description': 'Compute the cube of a value. The cube of x is x * x * x.', + 'examples': [ + 'cube(2)', + '2^3', + '2 * 2 * 2' + ], + 'seealso': [ + 'multiply', + 'square', + 'pow' + ] +}; diff --git a/lib/docs/function/arithmetic/divide.js b/lib/docs/function/arithmetic/divide.js new file mode 100644 index 000000000..fbc51a9f6 --- /dev/null +++ b/lib/docs/function/arithmetic/divide.js @@ -0,0 +1,20 @@ +module.exports = { + 'name': 'divide', + 'category': 'Operators', + 'syntax': [ + 'x / y', + 'divide(x, y)' + ], + 'description': 'Divide two values.', + 'examples': [ + '2 / 3', + 'ans * 3', + '4.5 / 2', + '3 + 4 / 2', + '(3 + 4) / 2', + '18 km / 4.5' + ], + 'seealso': [ + 'multiply' + ] +}; diff --git a/lib/docs/function/arithmetic/edivide.js b/lib/docs/function/arithmetic/edivide.js new file mode 100644 index 000000000..40c503d8d --- /dev/null +++ b/lib/docs/function/arithmetic/edivide.js @@ -0,0 +1,19 @@ +module.exports = { + 'name': 'edivide', + 'category': 'Operators', + 'syntax': [ + 'x ./ y', + 'edivide(x, y)' + ], + 'description': 'divide two values element wise.', + 'examples': [ + 'a = [1, 2, 3; 4, 5, 6]', + 'b = [2, 1, 1; 3, 2, 5]', + 'a ./ b' + ], + 'seealso': [ + 'multiply', + 'emultiply', + 'divide' + ] +}; diff --git a/lib/docs/function/arithmetic/emultiply.js b/lib/docs/function/arithmetic/emultiply.js new file mode 100644 index 000000000..909026da0 --- /dev/null +++ b/lib/docs/function/arithmetic/emultiply.js @@ -0,0 +1,19 @@ +module.exports = { + 'name': 'emultiply', + 'category': 'Operators', + 'syntax': [ + 'x .* y', + 'emultiply(x, y)' + ], + 'description': 'multiply two values element wise.', + 'examples': [ + 'a = [1, 2, 3; 4, 5, 6]', + 'b = [2, 1, 1; 3, 2, 5]', + 'a .* b' + ], + 'seealso': [ + 'multiply', + 'divide', + 'edivide' + ] +}; diff --git a/lib/docs/function/arithmetic/epow.js b/lib/docs/function/arithmetic/epow.js new file mode 100644 index 000000000..367c0f11d --- /dev/null +++ b/lib/docs/function/arithmetic/epow.js @@ -0,0 +1,17 @@ +module.exports = { + 'name': 'epow', + 'category': 'Operators', + 'syntax': [ + 'x .^ y', + 'epow(x, y)' + ], + 'description': + 'Calculates the power of x to y element wise.', + 'examples': [ + 'a = [1, 2, 3; 4, 5, 6]', + 'a .^ 2' + ], + 'seealso': [ + 'pow' + ] +}; diff --git a/lib/docs/function/arithmetic/equal.js b/lib/docs/function/arithmetic/equal.js new file mode 100644 index 000000000..e1b1eca27 --- /dev/null +++ b/lib/docs/function/arithmetic/equal.js @@ -0,0 +1,21 @@ +module.exports = { + 'name': 'equal', + 'category': 'Operators', + 'syntax': [ + 'x == y', + 'equal(x, y)' + ], + 'description': + 'Check equality of two values. Returns 1 if the values are equal, and 0 if not.', + 'examples': [ + '2+2 == 3', + '2+2 == 4', + 'a = 3.2', + 'b = 6-2.8', + 'a == b', + '50cm == 0.5m' + ], + 'seealso': [ + 'unequal', 'smaller', 'larger', 'smallereq', 'largereq' + ] +}; diff --git a/lib/docs/function/arithmetic/exp.js b/lib/docs/function/arithmetic/exp.js new file mode 100644 index 000000000..e3afaafb1 --- /dev/null +++ b/lib/docs/function/arithmetic/exp.js @@ -0,0 +1,20 @@ +module.exports = { + 'name': 'exp', + 'category': 'Arithmetic', + 'syntax': [ + 'exp(x)' + ], + 'description': 'Calculate the exponent of a value.', + 'examples': [ + 'exp(1.3)', + 'e ^ 1.3', + 'log(exp(1.3))', + 'x = 2.4', + '(exp(i*x) == cos(x) + i*sin(x)) # Euler\'s formula' + ], + 'seealso': [ + 'square', + 'multiply', + 'log' + ] +}; diff --git a/lib/docs/function/arithmetic/fix.js b/lib/docs/function/arithmetic/fix.js new file mode 100644 index 000000000..94f6b762a --- /dev/null +++ b/lib/docs/function/arithmetic/fix.js @@ -0,0 +1,16 @@ +module.exports = { + 'name': 'fix', + 'category': 'Arithmetic', + 'syntax': [ + 'fix(x)' + ], + 'description': + 'Round a value towards zero.If x is complex, both real and imaginary part are rounded towards zero.', + 'examples': [ + 'fix(3.2)', + 'fix(3.8)', + 'fix(-4.2)', + 'fix(-4.8)' + ], + 'seealso': ['ceil', 'floor', 'round'] +}; diff --git a/lib/docs/function/arithmetic/floor.js b/lib/docs/function/arithmetic/floor.js new file mode 100644 index 000000000..2075fd3ee --- /dev/null +++ b/lib/docs/function/arithmetic/floor.js @@ -0,0 +1,15 @@ +module.exports = { + 'name': 'floor', + 'category': 'Arithmetic', + 'syntax': [ + 'floor(x)' + ], + 'description': + 'Round a value towards minus infinity.If x is complex, both real and imaginary part are rounded towards minus infinity.', + 'examples': [ + 'floor(3.2)', + 'floor(3.8)', + 'floor(-4.2)' + ], + 'seealso': ['ceil', 'fix', 'round'] +}; diff --git a/lib/docs/function/arithmetic/gcd.js b/lib/docs/function/arithmetic/gcd.js new file mode 100644 index 000000000..160ceb138 --- /dev/null +++ b/lib/docs/function/arithmetic/gcd.js @@ -0,0 +1,15 @@ +module.exports = { + 'name': 'gcd', + 'category': 'Arithmetic', + 'syntax': [ + 'gcd(a, b)', + 'gcd(a, b, c, ...)' + ], + 'description': 'Compute the greatest common divisor.', + 'examples': [ + 'gcd(8, 12)', + 'gcd(-4, 6)', + 'gcd(25, 15, -10)' + ], + 'seealso': [ 'lcm', 'xgcd' ] +}; diff --git a/lib/docs/function/arithmetic/larger.js b/lib/docs/function/arithmetic/larger.js new file mode 100644 index 000000000..c7506d4f9 --- /dev/null +++ b/lib/docs/function/arithmetic/larger.js @@ -0,0 +1,22 @@ +module.exports = { + 'name': 'larger', + 'category': 'Operators', + 'syntax': [ + 'x > y', + 'larger(x, y)' + ], + 'description': + 'Check if value x is larger than y. Returns 1 if x is larger than y, and 0 if not.', + 'examples': [ + '2 > 3', + '5 > 2*2', + 'a = 3.3', + 'b = 6-2.8', + '(a > b)', + '(b < a)', + '5 cm > 2 inch' + ], + 'seealso': [ + 'equal', 'unequal', 'smaller', 'smallereq', 'largereq' + ] +}; diff --git a/lib/docs/function/arithmetic/largereq.js b/lib/docs/function/arithmetic/largereq.js new file mode 100644 index 000000000..3f6725b16 --- /dev/null +++ b/lib/docs/function/arithmetic/largereq.js @@ -0,0 +1,20 @@ +module.exports = { + 'name': 'largereq', + 'category': 'Operators', + 'syntax': [ + 'x >= y', + 'largereq(x, y)' + ], + 'description': + 'Check if value x is larger or equal to y. Returns 1 if x is larger or equal to y, and 0 if not.', + 'examples': [ + '2 > 1+1', + '2 >= 1+1', + 'a = 3.2', + 'b = 6-2.8', + '(a > b)' + ], + 'seealso': [ + 'equal', 'unequal', 'smallereq', 'smaller', 'largereq' + ] +}; diff --git a/lib/docs/function/arithmetic/lcm.js b/lib/docs/function/arithmetic/lcm.js new file mode 100644 index 000000000..c06bb0da5 --- /dev/null +++ b/lib/docs/function/arithmetic/lcm.js @@ -0,0 +1,14 @@ +module.exports = { + 'name': 'lcm', + 'category': 'Arithmetic', + 'syntax': [ + 'lcm(x, y)' + ], + 'description': 'Compute the least common multiple.', + 'examples': [ + 'lcm(4, 6)', + 'lcm(6, 21)', + 'lcm(6, 21, 5)' + ], + 'seealso': [ 'gcd' ] +}; diff --git a/lib/docs/function/arithmetic/log.js b/lib/docs/function/arithmetic/log.js new file mode 100644 index 000000000..1117d63fa --- /dev/null +++ b/lib/docs/function/arithmetic/log.js @@ -0,0 +1,23 @@ +module.exports = { + 'name': 'log', + 'category': 'Arithmetic', + 'syntax': [ + 'log(x)', + 'log(x, base)' + ], + 'description': 'Compute the logarithm of a value. If no base is provided, the natural logarithm of x is calculated. If base if provided, the logarithm is calculated for the specified base. log(x, base) is defined as log(x) / log(base).', + 'examples': [ + 'log(3.5)', + 'a = log(2.4)', + 'exp(a)', + '10 ^ 3', + 'log(1000, 10)', + 'log(1000) / log(10)', + 'b = logb(1024, 2)', + '2 ^ b' + ], + 'seealso': [ + 'exp', + 'log10' + ] +}; \ No newline at end of file diff --git a/lib/docs/function/arithmetic/log10.js b/lib/docs/function/arithmetic/log10.js new file mode 100644 index 000000000..4c1035875 --- /dev/null +++ b/lib/docs/function/arithmetic/log10.js @@ -0,0 +1,19 @@ +module.exports = { + 'name': 'log10', + 'category': 'Arithmetic', + 'syntax': [ + 'log10(x)' + ], + 'description': 'Compute the 10-base logarithm of a value.', + 'examples': [ + 'log10(1000)', + '10 ^ 3', + 'log10(0.01)', + 'log(1000) / log(10)', + 'log(1000, 10)' + ], + 'seealso': [ + 'exp', + 'log' + ] +}; diff --git a/lib/docs/function/arithmetic/mod.js b/lib/docs/function/arithmetic/mod.js new file mode 100644 index 000000000..8b96d915f --- /dev/null +++ b/lib/docs/function/arithmetic/mod.js @@ -0,0 +1,20 @@ +module.exports = { + 'name': 'mod', + 'category': 'Operators', + 'syntax': [ + 'x % y', + 'x mod y', + 'mod(x, y)' + ], + 'description': + 'Calculates the modulus, the remainder of an integer division.', + 'examples': [ + '7 % 3', + '11 % 2', + '10 mod 4', + 'function isOdd(x) = x % 2', + 'isOdd(2)', + 'isOdd(3)' + ], + 'seealso': [] +}; diff --git a/lib/docs/function/arithmetic/multiply.js b/lib/docs/function/arithmetic/multiply.js new file mode 100644 index 000000000..c808d35e6 --- /dev/null +++ b/lib/docs/function/arithmetic/multiply.js @@ -0,0 +1,19 @@ +module.exports = { + 'name': 'multiply', + 'category': 'Operators', + 'syntax': [ + 'x * y', + 'multiply(x, y)' + ], + 'description': 'multiply two values.', + 'examples': [ + '2.1 * 3.6', + 'ans / 3.6', + '2 * 3 + 4', + '2 * (3 + 4)', + '3 * 2.1 km' + ], + 'seealso': [ + 'divide' + ] +}; diff --git a/lib/docs/function/arithmetic/pow.js b/lib/docs/function/arithmetic/pow.js new file mode 100644 index 000000000..87fda66b7 --- /dev/null +++ b/lib/docs/function/arithmetic/pow.js @@ -0,0 +1,18 @@ +module.exports = { + 'name': 'pow', + 'category': 'Operators', + 'syntax': [ + 'x ^ y', + 'pow(x, y)' + ], + 'description': + 'Calculates the power of x to y, x^y.', + 'examples': [ + '2^3 = 8', + '2*2*2', + '1 + e ^ (pi * i)' + ], + 'seealso': [ + 'unequal', 'smaller', 'larger', 'smallereq', 'largereq' + ] +}; diff --git a/lib/docs/function/arithmetic/round.js b/lib/docs/function/arithmetic/round.js new file mode 100644 index 000000000..8dd193f0b --- /dev/null +++ b/lib/docs/function/arithmetic/round.js @@ -0,0 +1,19 @@ +module.exports = { + 'name': 'round', + 'category': 'Arithmetic', + 'syntax': [ + 'round(x)', + 'round(x, n)' + ], + 'description': + 'round a value towards the nearest integer.If x is complex, both real and imaginary part are rounded towards the nearest integer. When n is specified, the value is rounded to n decimals.', + 'examples': [ + 'round(3.2)', + 'round(3.8)', + 'round(-4.2)', + 'round(-4.8)', + 'round(pi, 3)', + 'round(123.45678, 2)' + ], + 'seealso': ['ceil', 'floor', 'fix'] +}; diff --git a/lib/docs/function/arithmetic/sign.js b/lib/docs/function/arithmetic/sign.js new file mode 100644 index 000000000..432196951 --- /dev/null +++ b/lib/docs/function/arithmetic/sign.js @@ -0,0 +1,17 @@ +module.exports = { + 'name': 'sign', + 'category': 'Arithmetic', + 'syntax': [ + 'sign(x)' + ], + 'description': + 'Compute the sign of a value. The sign of a value x is 1 when x>1, -1 when x<0, and 0 when x=0.', + 'examples': [ + 'sign(3.5)', + 'sign(-4.2)', + 'sign(0)' + ], + 'seealso': [ + 'abs' + ] +}; diff --git a/lib/docs/function/arithmetic/smaller.js b/lib/docs/function/arithmetic/smaller.js new file mode 100644 index 000000000..e6f7118de --- /dev/null +++ b/lib/docs/function/arithmetic/smaller.js @@ -0,0 +1,21 @@ +module.exports = { + 'name': 'smaller', + 'category': 'Operators', + 'syntax': [ + 'x < y', + 'smaller(x, y)' + ], + 'description': + 'Check if value x is smaller than value y. Returns 1 if x is smaller than y, and 0 if not.', + 'examples': [ + '2 < 3', + '5 < 2*2', + 'a = 3.3', + 'b = 6-2.8', + '(a < b)', + '5 cm < 2 inch' + ], + 'seealso': [ + 'equal', 'unequal', 'larger', 'smallereq', 'largereq' + ] +}; diff --git a/lib/docs/function/arithmetic/smallereq.js b/lib/docs/function/arithmetic/smallereq.js new file mode 100644 index 000000000..f52a1f5be --- /dev/null +++ b/lib/docs/function/arithmetic/smallereq.js @@ -0,0 +1,20 @@ +module.exports = { + 'name': 'smallereq', + 'category': 'Operators', + 'syntax': [ + 'x <= y', + 'smallereq(x, y)' + ], + 'description': + 'Check if value x is smaller or equal to value y. Returns 1 if x is smaller than y, and 0 if not.', + 'examples': [ + '2 < 1+1', + '2 <= 1+1', + 'a = 3.2', + 'b = 6-2.8', + '(a < b)' + ], + 'seealso': [ + 'equal', 'unequal', 'larger', 'smaller', 'largereq' + ] +}; diff --git a/lib/docs/function/arithmetic/sqrt.js b/lib/docs/function/arithmetic/sqrt.js new file mode 100644 index 000000000..d2d6d1cea --- /dev/null +++ b/lib/docs/function/arithmetic/sqrt.js @@ -0,0 +1,18 @@ +module.exports = { + 'name': 'sqrt', + 'category': 'Arithmetic', + 'syntax': [ + 'sqrt(x)' + ], + 'description': + 'Compute the square root value. If x = y * y, then y is the square root of x.', + 'examples': [ + 'sqrt(25)', + '5 * 5', + 'sqrt(-1)' + ], + 'seealso': [ + 'square', + 'multiply' + ] +}; diff --git a/lib/docs/function/arithmetic/square.js b/lib/docs/function/arithmetic/square.js new file mode 100644 index 000000000..99ccae2fc --- /dev/null +++ b/lib/docs/function/arithmetic/square.js @@ -0,0 +1,21 @@ +module.exports = { + 'name': 'square', + 'category': 'Arithmetic', + 'syntax': [ + 'square(x)' + ], + 'description': + 'Compute the square of a value. The square of x is x * x.', + 'examples': [ + 'square(3)', + 'sqrt(9)', + '3^2', + '3 * 3' + ], + 'seealso': [ + 'multiply', + 'pow', + 'sqrt', + 'cube' + ] +}; diff --git a/lib/docs/function/arithmetic/subtract.js b/lib/docs/function/arithmetic/subtract.js new file mode 100644 index 000000000..2ffefba6b --- /dev/null +++ b/lib/docs/function/arithmetic/subtract.js @@ -0,0 +1,19 @@ +module.exports = { + 'name': 'subtract', + 'category': 'Operators', + 'syntax': [ + 'x - y', + 'subtract(x, y)' + ], + 'description': 'subtract two values.', + 'examples': [ + '5.3 - 2', + 'ans + 2', + '2/3 - 1/6', + '2 * 3 - 3', + '2.1 km - 500m' + ], + 'seealso': [ + 'add' + ] +}; diff --git a/lib/docs/function/arithmetic/unary.js b/lib/docs/function/arithmetic/unary.js new file mode 100644 index 000000000..964b3acb6 --- /dev/null +++ b/lib/docs/function/arithmetic/unary.js @@ -0,0 +1,17 @@ +module.exports = { + 'name': 'unary', + 'category': 'Operators', + 'syntax': [ + '-x', + 'unary(x)' + ], + 'description': + 'Inverse the sign of a value.', + 'examples': [ + '-4.5', + '-(-5.6)' + ], + 'seealso': [ + 'add', 'subtract' + ] +}; diff --git a/lib/docs/function/arithmetic/unequal.js b/lib/docs/function/arithmetic/unequal.js new file mode 100644 index 000000000..2311c5aa6 --- /dev/null +++ b/lib/docs/function/arithmetic/unequal.js @@ -0,0 +1,22 @@ +module.exports = { + 'name': 'unequal', + 'category': 'Operators', + 'syntax': [ + 'x != y', + 'unequal(x, y)' + ], + 'description': + 'Check unequality of two values. Returns 1 if the values are unequal, and 0 if they are equal.', + 'examples': [ + '2+2 != 3', + '2+2 != 4', + 'a = 3.2', + 'b = 6-2.8', + 'a != b', + '50cm != 0.5m', + '5 cm != 2 inch' + ], + 'seealso': [ + 'equal', 'smaller', 'larger', 'smallereq', 'largereq' + ] +}; diff --git a/lib/docs/function/arithmetic/xgcd.js b/lib/docs/function/arithmetic/xgcd.js new file mode 100644 index 000000000..c7232ac22 --- /dev/null +++ b/lib/docs/function/arithmetic/xgcd.js @@ -0,0 +1,14 @@ +module.exports = { + 'name': 'xgcd', + 'category': 'Arithmetic', + 'syntax': [ + 'xgcd(a, b)' + ], + 'description': 'Calculate the extended greatest common divisor for two values', + 'examples': [ + 'xgcd(8, 12)', + 'gcd(8, 12)', + 'xgcd(36163, 21199)' + ], + 'seealso': [ 'gcd', 'lcm' ] +}; diff --git a/lib/docs/function/complex/arg.js b/lib/docs/function/complex/arg.js new file mode 100644 index 000000000..6f14b1fb8 --- /dev/null +++ b/lib/docs/function/complex/arg.js @@ -0,0 +1,20 @@ +module.exports = { + 'name': 'arg', + 'category': 'Complex', + 'syntax': [ + 'arg(x)' + ], + 'description': + 'Compute the argument of a complex value. If x = a+bi, the argument is computed as atan2(b, a).', + 'examples': [ + 'arg(2 + 2i)', + 'atan2(3, 2)', + 'arg(2 - 3i)' + ], + 'seealso': [ + 're', + 'im', + 'conj', + 'abs' + ] +}; diff --git a/lib/docs/function/complex/conj.js b/lib/docs/function/complex/conj.js new file mode 100644 index 000000000..b57b9813d --- /dev/null +++ b/lib/docs/function/complex/conj.js @@ -0,0 +1,20 @@ +module.exports = { + 'name': 'conj', + 'category': 'Complex', + 'syntax': [ + 'conj(x)' + ], + 'description': + 'Compute the complex conjugate of a complex value. If x = a+bi, the complex conjugate is a-bi.', + 'examples': [ + 'conj(2 + 3i)', + 'conj(2 - 3i)', + 'conj(-5.2i)' + ], + 'seealso': [ + 're', + 'im', + 'abs', + 'arg' + ] +}; diff --git a/lib/docs/function/complex/im.js b/lib/docs/function/complex/im.js new file mode 100644 index 000000000..7608d6575 --- /dev/null +++ b/lib/docs/function/complex/im.js @@ -0,0 +1,20 @@ +module.exports = { + 'name': 'im', + 'category': 'Complex', + 'syntax': [ + 'im(x)' + ], + 'description': 'Get the imaginary part of a complex number.', + 'examples': [ + 'im(2 + 3i)', + 're(2 + 3i)', + 'im(-5.2i)', + 'im(2.4)' + ], + 'seealso': [ + 're', + 'conj', + 'abs', + 'arg' + ] +}; diff --git a/lib/docs/function/complex/re.js b/lib/docs/function/complex/re.js new file mode 100644 index 000000000..6fa53efeb --- /dev/null +++ b/lib/docs/function/complex/re.js @@ -0,0 +1,20 @@ +module.exports = { + 'name': 're', + 'category': 'Complex', + 'syntax': [ + 're(x)' + ], + 'description': 'Get the real part of a complex number.', + 'examples': [ + 're(2 + 3i)', + 'im(2 + 3i)', + 're(-5.2i)', + 're(2.4)' + ], + 'seealso': [ + 'im', + 'conj', + 'abs', + 'arg' + ] +}; diff --git a/lib/docs/function/construction/boolean.js b/lib/docs/function/construction/boolean.js new file mode 100644 index 000000000..5d830a2b0 --- /dev/null +++ b/lib/docs/function/construction/boolean.js @@ -0,0 +1,20 @@ +module.exports = { + 'name': 'boolean', + 'category': 'Type', + 'syntax': [ + 'x', + 'boolean(x)' + ], + 'description': + 'Convert a string or number into a boolean.', + 'examples': [ + 'boolean(0)', + 'boolean(1)', + 'boolean(3)', + 'boolean("true")', + 'boolean("false")' + ], + 'seealso': [ + 'complex', 'matrix', 'range', 'string', 'unit' + ] +}; diff --git a/lib/docs/function/construction/complex.js b/lib/docs/function/construction/complex.js new file mode 100644 index 000000000..76882d6f9 --- /dev/null +++ b/lib/docs/function/construction/complex.js @@ -0,0 +1,19 @@ +module.exports = { + 'name': 'complex', + 'category': 'Type', + 'syntax': [ + 'complex()', + 'complex(re, im)', + 'complex(string)' + ], + 'description': + 'Create a complex number.', + 'examples': [ + 'complex()', + 'complex(2, 3)', + 'complex("7 - 2i")' + ], + 'seealso': [ + 'boolean', 'matrix', 'number', 'range', 'string', 'unit' + ] +}; diff --git a/lib/docs/function/construction/matrix.js b/lib/docs/function/construction/matrix.js new file mode 100644 index 000000000..513b11e9e --- /dev/null +++ b/lib/docs/function/construction/matrix.js @@ -0,0 +1,22 @@ +module.exports = { + 'name': 'matrix', + 'category': 'Type', + 'syntax': [ + '[]', + '[a1, b1, ...; a2, b2, ...]', + 'matrix()', + 'matrix([...])' + ], + 'description': + 'Create a matrix.', + 'examples': [ + '[]', + '[1, 2, 3]', + '[1, 2, 3; 4, 5, 6]', + 'matrix()', + 'matrix([3, 4])' + ], + 'seealso': [ + 'boolean', 'complex', 'number', 'range', 'string', 'unit' + ] +}; diff --git a/lib/docs/function/construction/number.js b/lib/docs/function/construction/number.js new file mode 100644 index 000000000..72cf9a97a --- /dev/null +++ b/lib/docs/function/construction/number.js @@ -0,0 +1,21 @@ +module.exports = { + 'name': 'number', + 'category': 'Type', + 'syntax': [ + 'x', + 'number(x)' + ], + 'description': + 'Create a number or convert a string or boolean into a number.', + 'examples': [ + '2', + '2e3', + '4.05', + 'number(2)', + 'number("7.2")', + 'number(true)' + ], + 'seealso': [ + 'boolean', 'complex', 'matrix', 'range', 'string', 'unit' + ] +}; diff --git a/lib/docs/function/construction/range.js b/lib/docs/function/construction/range.js new file mode 100644 index 000000000..1b8e5512c --- /dev/null +++ b/lib/docs/function/construction/range.js @@ -0,0 +1,25 @@ +module.exports = { + 'name': 'range', + 'category': 'Type', + 'syntax': [ + 'start:end', + 'start:step:end', + 'range(start, end)', + 'range(start, end, step)', + 'range(string)' + ], + 'description': + 'Create a range. Lower bound of the range is included, upper bound is excluded.', + 'examples': [ + '1:5', + '3:-1:-4', + 'range(3, 7)', + 'range(0, 12, 2)', + 'range("4:11")', + 'a = [0, 1, 2, 3; 4, 5, 6]', + 'a(1:2)' + ], + 'seealso': [ + 'boolean', 'complex', 'matrix', 'number', 'string', 'unit' + ] +}; diff --git a/lib/docs/function/construction/string.js b/lib/docs/function/construction/string.js new file mode 100644 index 000000000..ceb6b42dd --- /dev/null +++ b/lib/docs/function/construction/string.js @@ -0,0 +1,18 @@ +module.exports = { + 'name': 'string', + 'category': 'Type', + 'syntax': [ + '"text"', + 'string(x)' + ], + 'description': + 'Create a string or convert a value to a string', + 'examples': [ + '"Hello World!"', + 'string(4.2)', + 'string(3 + 2i)' + ], + 'seealso': [ + 'boolean', 'complex', 'matrix', 'number', 'range', 'unit' + ] +}; diff --git a/lib/docs/function/construction/unit.js b/lib/docs/function/construction/unit.js new file mode 100644 index 000000000..5917182c9 --- /dev/null +++ b/lib/docs/function/construction/unit.js @@ -0,0 +1,20 @@ +module.exports = { + 'name': 'unit', + 'category': 'Type', + 'syntax': [ + 'value unit', + 'unit(value, unit)', + 'unit(string)' + ], + 'description': + 'Create a unit.', + 'examples': [ + '5.5 mm', + '3 inch', + 'unit(7.1, "kilogram")', + 'unit("23 deg")' + ], + 'seealso': [ + 'boolean', 'complex', 'matrix', 'number', 'range', 'string' + ] +}; diff --git a/lib/docs/function/matrix/concat.js b/lib/docs/function/matrix/concat.js new file mode 100644 index 000000000..270fadf91 --- /dev/null +++ b/lib/docs/function/matrix/concat.js @@ -0,0 +1,20 @@ +module.exports = { + 'name': 'concat', + 'category': 'Matrix', + 'syntax': [ + 'concat(a, b, c, ...)', + 'concat(a, b, c, ..., dim)' + ], + 'description': 'Concatenate matrices. By default, the matrices are concatenated by the first dimension. The dimension on which to concatenate can be provided as last argument.', + 'examples': [ + 'a = [1, 2; 5, 6]', + 'b = [3, 4; 7, 8]', + 'concat(a, b)', + '[a, b]', + 'concat(a, b, 2)', + '[a; b]' + ], + 'seealso': [ + 'det', 'diag', 'eye', 'inv', 'ones', 'size', 'squeeze', 'subset', 'transpose', 'zeros' + ] +}; diff --git a/lib/docs/function/matrix/det.js b/lib/docs/function/matrix/det.js new file mode 100644 index 000000000..aafb283e2 --- /dev/null +++ b/lib/docs/function/matrix/det.js @@ -0,0 +1,15 @@ +module.exports = { + 'name': 'det', + 'category': 'Matrix', + 'syntax': [ + 'det(x)' + ], + 'description': 'Calculate the determinant of a matrix', + 'examples': [ + 'det([1, 2; 3, 4])', + 'det([-2, 2, 3; -1, 1, 3; 2, 0, -1])' + ], + 'seealso': [ + 'concat', 'diag', 'eye', 'inv', 'ones', 'size', 'squeeze', 'subset', 'transpose', 'zeros' + ] +}; diff --git a/lib/docs/function/matrix/diag.js b/lib/docs/function/matrix/diag.js new file mode 100644 index 000000000..473d87530 --- /dev/null +++ b/lib/docs/function/matrix/diag.js @@ -0,0 +1,18 @@ +module.exports = { + 'name': 'diag', + 'category': 'Matrix', + 'syntax': [ + 'diag(x)', + 'diag(x, k)' + ], + 'description': 'Create a diagonal matrix or retrieve the diagonal of a matrix. When x is a vector, a matrix with the vector values on the diagonal will be returned. When x is a matrix, a vector with the diagonal values of the matrix is returned.When k is provided, the k-th diagonal will be filled in or retrieved, if k is positive, the values are placed on the super diagonal. When k is negative, the values are placed on the sub diagonal.', + 'examples': [ + 'diag(1:4)', + 'diag(1:4, 1)', + 'a = [1, 2, 3; 4, 5, 6; 7, 8, 9]', + 'diag(a)' + ], + 'seealso': [ + 'concat', 'det', 'eye', 'inv', 'ones', 'size', 'squeeze', 'subset', 'transpose', 'zeros' + ] +}; diff --git a/lib/docs/function/matrix/eye.js b/lib/docs/function/matrix/eye.js new file mode 100644 index 000000000..5163b840d --- /dev/null +++ b/lib/docs/function/matrix/eye.js @@ -0,0 +1,20 @@ +module.exports = { + 'name': 'eye', + 'category': 'Matrix', + 'syntax': [ + 'eye(n)', + 'eye(m, n)', + 'eye([m, n])', + 'eye' + ], + 'description': 'Returns the identity matrix with size m-by-n. The matrix has ones on the diagonal and zeros elsewhere.', + 'examples': [ + 'eye(3)', + 'eye(3, 5)', + 'a = [1, 2, 3; 4, 5, 6]', + 'eye(size(a))' + ], + 'seealso': [ + 'concat', 'det', 'diag', 'inv', 'ones', 'size', 'squeeze', 'subset', 'transpose', 'zeros' + ] +}; diff --git a/lib/docs/function/matrix/inv.js b/lib/docs/function/matrix/inv.js new file mode 100644 index 000000000..2afe90f5f --- /dev/null +++ b/lib/docs/function/matrix/inv.js @@ -0,0 +1,16 @@ +module.exports = { + 'name': 'inv', + 'category': 'Matrix', + 'syntax': [ + 'inv(x)' + ], + 'description': 'Calculate the inverse of a matrix', + 'examples': [ + 'inv([1, 2; 3, 4])', + 'inv(4)', + '1 / 4' + ], + 'seealso': [ + 'concat', 'det', 'diag', 'eye', 'ones', 'size', 'squeeze', 'subset', 'transpose', 'zeros' + ] +}; diff --git a/lib/docs/function/matrix/ones.js b/lib/docs/function/matrix/ones.js new file mode 100644 index 000000000..c2d7f31b1 --- /dev/null +++ b/lib/docs/function/matrix/ones.js @@ -0,0 +1,23 @@ +module.exports = { + 'name': 'ones', + 'category': 'Matrix', + 'syntax': [ + 'ones(n)', + 'ones(m, n)', + 'ones(m, n, p, ...)', + 'ones([m, n])', + 'ones([m, n, p, ...])', + 'ones' + ], + 'description': 'Create a matrix containing ones.', + 'examples': [ + 'ones(3)', + 'ones(3, 5)', + 'ones([2,3]) * 4.5', + 'a = [1, 2, 3; 4, 5, 6]', + 'ones(size(a))' + ], + 'seealso': [ + 'concat', 'det', 'diag', 'eye', 'inv', 'size', 'squeeze', 'subset', 'transpose', 'zeros' + ] +}; diff --git a/lib/docs/function/matrix/size.js b/lib/docs/function/matrix/size.js new file mode 100644 index 000000000..b41856a74 --- /dev/null +++ b/lib/docs/function/matrix/size.js @@ -0,0 +1,18 @@ +module.exports = { + 'name': 'size', + 'category': 'Matrix', + 'syntax': [ + 'size(x)' + ], + 'description': 'Calculate the size of a matrix.', + 'examples': [ + 'size(2.3)', + 'size("hello world")', + 'a = [1, 2; 3, 4; 5, 6]', + 'size(a)', + 'size(1:6)' + ], + 'seealso': [ + 'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'squeeze', 'subset', 'transpose', 'zeros' + ] +}; diff --git a/lib/docs/function/matrix/squeeze.js b/lib/docs/function/matrix/squeeze.js new file mode 100644 index 000000000..adfdd48f6 --- /dev/null +++ b/lib/docs/function/matrix/squeeze.js @@ -0,0 +1,17 @@ +module.exports = { + 'name': 'squeeze', + 'category': 'Matrix', + 'syntax': [ + 'squeeze(x)' + ], + 'description': 'Remove singleton dimensions from a matrix.', + 'examples': [ + 'a = zeros(1,3,2)', + 'size(squeeze(a))', + 'b = zeros(3,1,1)', + 'size(squeeze(b))' + ], + 'seealso': [ + 'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'size', 'subset', 'transpose', 'zeros' + ] +}; diff --git a/lib/docs/function/matrix/subset.js b/lib/docs/function/matrix/subset.js new file mode 100644 index 000000000..a99f11e69 --- /dev/null +++ b/lib/docs/function/matrix/subset.js @@ -0,0 +1,23 @@ +module.exports = { + 'name': 'subset', + 'category': 'Matrix', + 'syntax': [ + 'value(index)', + 'value(index) = replacement', + 'subset(value, [index])', + 'subset(value, [index], replacement)' + ], + 'description': 'Get or set a subset of a matrix or string.', + 'examples': [ + 'd = [1, 2; 3, 4]', + 'e = []', + 'e(0, 0:1) = [5, 6]', + 'e(1, :) = [7, 8]', + 'f = d * e', + 'f(1, 0)', + 'f(:, 0)' + ], + 'seealso': [ + 'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'range', 'size', 'squeeze', 'transpose', 'zeros' + ] +}; diff --git a/lib/docs/function/matrix/transpose.js b/lib/docs/function/matrix/transpose.js new file mode 100644 index 000000000..f0fbca22e --- /dev/null +++ b/lib/docs/function/matrix/transpose.js @@ -0,0 +1,17 @@ +module.exports = { + 'name': 'transpose', + 'category': 'Matrix', + 'syntax': [ + 'x\'', + 'transpose(x)' + ], + 'description': 'Transpose a matrix', + 'examples': [ + 'a = [1, 2, 3; 4, 5, 6]', + 'a\'', + 'transpose(a)' + ], + 'seealso': [ + 'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'size', 'squeeze', 'subset', 'zeros' + ] +}; diff --git a/lib/docs/function/matrix/zeros.js b/lib/docs/function/matrix/zeros.js new file mode 100644 index 000000000..4a4506bbc --- /dev/null +++ b/lib/docs/function/matrix/zeros.js @@ -0,0 +1,22 @@ +module.exports = { + 'name': 'zeros', + 'category': 'Matrix', + 'syntax': [ + 'zeros(n)', + 'zeros(m, n)', + 'zeros(m, n, p, ...)', + 'zeros([m, n])', + 'zeros([m, n, p, ...])', + 'zeros' + ], + 'description': 'Create a matrix containing zeros.', + 'examples': [ + 'zeros(3)', + 'zeros(3, 5)', + 'a = [1, 2, 3; 4, 5, 6]', + 'zeros(size(a))' + ], + 'seealso': [ + 'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'size', 'squeeze', 'subset', 'transpose' + ] +}; diff --git a/lib/docs/function/probability/factorial.js b/lib/docs/function/probability/factorial.js new file mode 100644 index 000000000..dc146cda0 --- /dev/null +++ b/lib/docs/function/probability/factorial.js @@ -0,0 +1,15 @@ +module.exports = { + 'name': 'factorial', + 'category': 'Probability', + 'syntax': [ + 'x!', + 'factorial(x)' + ], + 'description': 'Compute the factorial of a value', + 'examples': [ + '5!', + '5*4*3*2*1', + '3!' + ], + 'seealso': [] +}; diff --git a/lib/docs/function/probability/random.js b/lib/docs/function/probability/random.js new file mode 100644 index 000000000..9a04f643c --- /dev/null +++ b/lib/docs/function/probability/random.js @@ -0,0 +1,13 @@ +module.exports = { + 'name': 'random', + 'category': 'Probability', + 'syntax': [ + 'random(min, max)' + ], + 'description': + 'Return a random number between 0 and 1.', + 'examples': [ + 'random()' + ], + 'seealso': [] +}; diff --git a/lib/docs/function/probability/randomInt.js b/lib/docs/function/probability/randomInt.js new file mode 100644 index 000000000..f0da378e8 --- /dev/null +++ b/lib/docs/function/probability/randomInt.js @@ -0,0 +1,13 @@ +module.exports = { + 'name': 'randInt', + 'category': 'Probability', + 'syntax': [ + 'randInt()' + ], + 'description': + 'Return a random number between 0 and 1.', + 'examples': [ + 'randInt()' + ], + 'seealso': [] +}; \ No newline at end of file diff --git a/lib/docs/function/statistics/max.js b/lib/docs/function/statistics/max.js new file mode 100644 index 000000000..5941a0e72 --- /dev/null +++ b/lib/docs/function/statistics/max.js @@ -0,0 +1,22 @@ +module.exports = { + 'name': 'max', + 'category': 'Statistics', + 'syntax': [ + 'max(a, b, c, ...)' + ], + 'description': 'Compute the maximum value of a list of values.', + 'examples': [ + 'max(2, 3, 4, 1)', + 'max(2.7, 7.1, -4.5, 2.0, 4.1)', + 'min(2.7, 7.1, -4.5, 2.0, 4.1)' + ], + 'seealso': [ + //'sum', + //'prod', + //'avg', + //'var', + //'std', + 'min' + //'median' + ] +}; diff --git a/lib/docs/function/statistics/min.js b/lib/docs/function/statistics/min.js new file mode 100644 index 000000000..adfb7f487 --- /dev/null +++ b/lib/docs/function/statistics/min.js @@ -0,0 +1,22 @@ +module.exports = { + 'name': 'min', + 'category': 'Statistics', + 'syntax': [ + 'min(a, b, c, ...)' + ], + 'description': 'Compute the minimum value of a list of values.', + 'examples': [ + 'min(2, 3, 4, 1)', + 'min(2.7, 7.1, -4.5, 2.0, 4.1)', + 'max(2.7, 7.1, -4.5, 2.0, 4.1)' + ], + 'seealso': [ + //'sum', + //'prod', + //'avg', + //'var', + //'std', + 'max' + //'median' + ] +}; diff --git a/lib/docs/function/trigonometry/acos.js b/lib/docs/function/trigonometry/acos.js new file mode 100644 index 000000000..78ffe9da6 --- /dev/null +++ b/lib/docs/function/trigonometry/acos.js @@ -0,0 +1,17 @@ +module.exports = { + 'name': 'acos', + 'category': 'Trigonometry', + 'syntax': [ + 'acos(x)' + ], + 'description': 'Compute the inverse cosine of a value in radians.', + 'examples': [ + 'acos(0.5)', + 'acos(cos(2.3))' + ], + 'seealso': [ + 'cos', + 'acos', + 'asin' + ] +}; diff --git a/lib/docs/function/trigonometry/asin.js b/lib/docs/function/trigonometry/asin.js new file mode 100644 index 000000000..6e53189e0 --- /dev/null +++ b/lib/docs/function/trigonometry/asin.js @@ -0,0 +1,17 @@ +module.exports = { + 'name': 'asin', + 'category': 'Trigonometry', + 'syntax': [ + 'asin(x)' + ], + 'description': 'Compute the inverse sine of a value in radians.', + 'examples': [ + 'asin(0.5)', + 'asin(sin(2.3))' + ], + 'seealso': [ + 'sin', + 'acos', + 'asin' + ] +}; diff --git a/lib/docs/function/trigonometry/atan.js b/lib/docs/function/trigonometry/atan.js new file mode 100644 index 000000000..4780256da --- /dev/null +++ b/lib/docs/function/trigonometry/atan.js @@ -0,0 +1,17 @@ +module.exports = { + 'name': 'atan', + 'category': 'Trigonometry', + 'syntax': [ + 'atan(x)' + ], + 'description': 'Compute the inverse tangent of a value in radians.', + 'examples': [ + 'atan(0.5)', + 'atan(tan(2.3))' + ], + 'seealso': [ + 'tan', + 'acos', + 'asin' + ] +}; diff --git a/lib/docs/function/trigonometry/atan2.js b/lib/docs/function/trigonometry/atan2.js new file mode 100644 index 000000000..da6dc5a29 --- /dev/null +++ b/lib/docs/function/trigonometry/atan2.js @@ -0,0 +1,21 @@ +module.exports = { + 'name': 'atan2', + 'category': 'Trigonometry', + 'syntax': [ + 'atan2(y, x)' + ], + 'description': + 'Computes the principal value of the arc tangent of y/x in radians.', + 'examples': [ + 'atan2(2, 2) / pi', + 'angle = 60 deg in rad', + 'x = cos(angle)', + 'y = sin(angle)', + 'atan2(y, x)' + ], + 'seealso': [ + 'sin', + 'cos', + 'tan' + ] +}; diff --git a/lib/docs/function/trigonometry/cos.js b/lib/docs/function/trigonometry/cos.js new file mode 100644 index 000000000..412df2baf --- /dev/null +++ b/lib/docs/function/trigonometry/cos.js @@ -0,0 +1,20 @@ +module.exports = { + 'name': 'cos', + 'category': 'Trigonometry', + 'syntax': [ + 'cos(x)' + ], + 'description': 'Compute the cosine of x in radians.', + 'examples': [ + 'cos(2)', + 'cos(pi / 4) ^ 2', + 'cos(180 deg)', + 'cos(60 deg)', + 'sin(0.2)^2 + cos(0.2)^2' + ], + 'seealso': [ + 'acos', + 'sin', + 'tan' + ] +}; diff --git a/lib/docs/function/trigonometry/cot.js b/lib/docs/function/trigonometry/cot.js new file mode 100644 index 000000000..1d7fa12b8 --- /dev/null +++ b/lib/docs/function/trigonometry/cot.js @@ -0,0 +1,17 @@ +module.exports = { + 'name': 'cot', + 'category': 'Trigonometry', + 'syntax': [ + 'cot(x)' + ], + 'description': 'Compute the cotangent of x in radians. Defined as 1/tan(x)', + 'examples': [ + 'cot(2)', + '1 / tan(2)' + ], + 'seealso': [ + 'sec', + 'csc', + 'tan' + ] +}; diff --git a/lib/docs/function/trigonometry/csc.js b/lib/docs/function/trigonometry/csc.js new file mode 100644 index 000000000..bfe7d6fde --- /dev/null +++ b/lib/docs/function/trigonometry/csc.js @@ -0,0 +1,17 @@ +module.exports = { + 'name': 'csc', + 'category': 'Trigonometry', + 'syntax': [ + 'csc(x)' + ], + 'description': 'Compute the cosecant of x in radians. Defined as 1/sin(x)', + 'examples': [ + 'csc(2)', + '1 / sin(2)' + ], + 'seealso': [ + 'sec', + 'cot', + 'sin' + ] +}; diff --git a/lib/docs/function/trigonometry/sec.js b/lib/docs/function/trigonometry/sec.js new file mode 100644 index 000000000..9b931aa6a --- /dev/null +++ b/lib/docs/function/trigonometry/sec.js @@ -0,0 +1,17 @@ +module.exports = { + 'name': 'sec', + 'category': 'Trigonometry', + 'syntax': [ + 'sec(x)' + ], + 'description': 'Compute the secant of x in radians. Defined as 1/cos(x)', + 'examples': [ + 'sec(2)', + '1 / cos(2)' + ], + 'seealso': [ + 'cot', + 'csc', + 'cos' + ] +}; diff --git a/lib/docs/function/trigonometry/sin.js b/lib/docs/function/trigonometry/sin.js new file mode 100644 index 000000000..6d6f7f7a8 --- /dev/null +++ b/lib/docs/function/trigonometry/sin.js @@ -0,0 +1,20 @@ +module.exports = { + 'name': 'sin', + 'category': 'Trigonometry', + 'syntax': [ + 'sin(x)' + ], + 'description': 'Compute the sine of x in radians.', + 'examples': [ + 'sin(2)', + 'sin(pi / 4) ^ 2', + 'sin(90 deg)', + 'sin(30 deg)', + 'sin(0.2)^2 + cos(0.2)^2' + ], + 'seealso': [ + 'asin', + 'cos', + 'tan' + ] +}; diff --git a/lib/docs/function/trigonometry/tan.js b/lib/docs/function/trigonometry/tan.js new file mode 100644 index 000000000..14c281982 --- /dev/null +++ b/lib/docs/function/trigonometry/tan.js @@ -0,0 +1,19 @@ +module.exports = { + 'name': 'tan', + 'category': 'Trigonometry', + 'syntax': [ + 'tan(x)' + ], + 'description': 'Compute the tangent of x in radians.', + 'examples': [ + 'tan(0.5)', + 'sin(0.5) / cos(0.5)', + 'tan(pi / 4)', + 'tan(45 deg)' + ], + 'seealso': [ + 'atan', + 'sin', + 'cos' + ] +}; diff --git a/lib/docs/function/units/in.js b/lib/docs/function/units/in.js new file mode 100644 index 000000000..572c7f350 --- /dev/null +++ b/lib/docs/function/units/in.js @@ -0,0 +1,15 @@ +module.exports = { + 'name': 'in', + 'category': 'Units', + 'syntax': [ + 'x in unit', + 'in(x, unit)' + ], + 'description': 'Change the unit of a value.', + 'examples': [ + '5 inch in cm', + '3.2kg in g', + '16 bytes in bits' + ], + 'seealso': [] +}; diff --git a/lib/docs/function/utils/clone.js b/lib/docs/function/utils/clone.js new file mode 100644 index 000000000..18ca109c3 --- /dev/null +++ b/lib/docs/function/utils/clone.js @@ -0,0 +1,16 @@ +module.exports = { + 'name': 'clone', + 'category': 'Utils', + 'syntax': [ + 'clone(x)' + ], + 'description': 'Clone a variable. Creates a copy of primitive variables,and a deep copy of matrices', + 'examples': [ + 'clone(3.5)', + 'clone(2 - 4i)', + 'clone(45 deg)', + 'clone([1, 2; 3, 4])', + 'clone("hello world")' + ], + 'seealso': [] +}; diff --git a/lib/docs/function/utils/eval.js b/lib/docs/function/utils/eval.js new file mode 100644 index 000000000..0eba6892e --- /dev/null +++ b/lib/docs/function/utils/eval.js @@ -0,0 +1,14 @@ +module.exports = { + 'name': 'eval', + 'category': 'Utils', + 'syntax': [ + 'eval(expression)', + 'eval([expr1, expr2, expr3, ...])' + ], + 'description': 'Evaluate an expression or an array with expressions.', + 'examples': [ + 'eval("2 + 3")', + 'eval("sqrt(" + 4 + ")")' + ], + 'seealso': [] +}; diff --git a/lib/docs/function/utils/format.js b/lib/docs/function/utils/format.js new file mode 100644 index 000000000..98ad21f5f --- /dev/null +++ b/lib/docs/function/utils/format.js @@ -0,0 +1,14 @@ +module.exports = { + 'name': 'format', + 'category': 'Utils', + 'syntax': [ + 'format(value)' + ], + 'description': 'Format a value of any type as string.', + 'examples': [ + 'format(2.3)', + 'format(3 - 4i)', + 'format([])' + ], + 'seealso': [] +}; diff --git a/lib/docs/function/utils/help.js b/lib/docs/function/utils/help.js new file mode 100644 index 000000000..20a011a0b --- /dev/null +++ b/lib/docs/function/utils/help.js @@ -0,0 +1,14 @@ +module.exports = { + 'name': 'help', + 'category': 'Utils', + 'syntax': [ + 'help(object)', + 'help(string)' + ], + 'description': 'Display documentation on a function or data type.', + 'examples': [ + 'help(sqrt)', + 'help("complex")' + ], + 'seealso': [] +}; diff --git a/lib/docs/function/utils/import.js b/lib/docs/function/utils/import.js new file mode 100644 index 000000000..b9efc92cf --- /dev/null +++ b/lib/docs/function/utils/import.js @@ -0,0 +1,13 @@ +module.exports = { + 'name': 'import', + 'category': 'Utils', + 'syntax': [ + 'import(string)' + ], + 'description': 'Import functions from a file.', + 'examples': [ + 'import("numbers")', + 'import("./mylib.js")' + ], + 'seealso': [] +}; diff --git a/lib/docs/function/utils/typeof.js b/lib/docs/function/utils/typeof.js new file mode 100644 index 000000000..71e329bc9 --- /dev/null +++ b/lib/docs/function/utils/typeof.js @@ -0,0 +1,15 @@ +module.exports = { + 'name': 'typeof', + 'category': 'Utils', + 'syntax': [ + 'typeof(x)' + ], + 'description': 'Get the type of a variable.', + 'examples': [ + 'typeof(3.5)', + 'typeof(2 - 4i)', + 'typeof(45 deg)', + 'typeof("hello world")' + ], + 'seealso': [] +}; diff --git a/lib/docs/index.js b/lib/docs/index.js new file mode 100644 index 000000000..21b82313b --- /dev/null +++ b/lib/docs/index.js @@ -0,0 +1,110 @@ +// constants +exports.e = require('./constants/e.js'); +exports.E = require('./constants/e.js'); +exports['false'] = require('./constants/false.js'); +exports.i = require('./constants/i.js'); +exports['Infinity'] = require('./constants/Infinity.js'); +exports.LN2 = require('./constants/LN2.js'); +exports.LN10 = require('./constants/LN10.js'); +exports.LOG2E = require('./constants/LOG2E.js'); +exports.LOG10E = require('./constants/LOG10E.js'); +exports.NaN = require('./constants/NaN.js'); +exports.pi = require('./constants/pi.js'); +exports.PI = require('./constants/pi.js'); +exports.SQRT1_2 = require('./constants/SQRT1_2.js'); +exports.SQRT2 = require('./constants/SQRT2.js'); +exports.tau = require('./constants/tau.js'); +exports['true'] = require('./constants/true.js'); + +// functions - arithmetic +exports.abs = require('./function/arithmetic/abs.js'); +exports.add = require('./function/arithmetic/add.js'); +exports.ceil = require('./function/arithmetic/ceil.js'); +exports.cube = require('./function/arithmetic/cube.js'); +exports.divide = require('./function/arithmetic/divide.js'); +exports.edivide = require('./function/arithmetic/edivide.js'); +exports.emultiply = require('./function/arithmetic/emultiply.js'); +exports.epow = require('./function/arithmetic/epow.js'); +exports.equal = require('./function/arithmetic/equal.js'); +exports.exp = require('./function/arithmetic/exp.js'); +exports.fix = require('./function/arithmetic/fix.js'); +exports.floor = require('./function/arithmetic/floor.js'); +exports.gcd = require('./function/arithmetic/gcd.js'); +exports.larger = require('./function/arithmetic/larger.js'); +exports.largereq = require('./function/arithmetic/largereq.js'); +exports.lcm = require('./function/arithmetic/lcm.js'); +exports.log = require('./function/arithmetic/log.js'); +exports.log10 = require('./function/arithmetic/log10.js'); +exports.mod = require('./function/arithmetic/mod.js'); +exports.multiply = require('./function/arithmetic/multiply.js'); +exports.pow = require('./function/arithmetic/pow.js'); +exports.round = require('./function/arithmetic/round.js'); +exports.sign = require('./function/arithmetic/sign.js'); +exports.smaller = require('./function/arithmetic/smaller.js'); +exports.smallereq = require('./function/arithmetic/smallereq.js'); +exports.sqrt = require('./function/arithmetic/sqrt.js'); +exports.square = require('./function/arithmetic/square.js'); +exports.subtract = require('./function/arithmetic/subtract.js'); +exports.unary = require('./function/arithmetic/unary.js'); +exports.unequal = require('./function/arithmetic/unequal.js'); +exports.xgcd = require('./function/arithmetic/xgcd.js'); + +// functions - complex +exports.arg = require('./function/complex/arg.js'); +exports.conj = require('./function/complex/conj.js'); +exports.re = require('./function/complex/re.js'); +exports.im = require('./function/complex/im.js'); + +// functions - construction +exports.boolean = require('./function/construction/boolean.js'); +exports.complex = require('./function/construction/complex.js'); +exports.matrix = require('./function/construction/matrix.js'); +exports.number = require('./function/construction/number.js'); +exports.range = require('./function/construction/range.js'); +exports.string = require('./function/construction/string.js'); +exports.unit = require('./function/construction/unit.js'); + +// functions - matrix +exports.concat = require('./function/matrix/concat.js'); +exports.det = require('./function/matrix/det.js'); +exports.diag = require('./function/matrix/diag.js'); +exports.eye = require('./function/matrix/eye.js'); +exports.inv = require('./function/matrix/inv.js'); +exports.ones = require('./function/matrix/ones.js'); +exports.size = require('./function/matrix/size.js'); +exports.squeeze = require('./function/matrix/squeeze.js'); +exports.subset = require('./function/matrix/subset.js'); +exports.transpose = require('./function/matrix/transpose.js'); +exports.zeros = require('./function/matrix/zeros.js'); + +// functions - probability +exports.factorial = require('./function/probability/factorial.js'); +exports.random = require('./function/probability/random.js'); +exports.randomInt = require('./function/probability/randomInt.js'); + +// functions - statistics +exports.min = require('./function/statistics/min.js'); +exports.max = require('./function/statistics/max.js'); + +// functions - trigonometry +exports.acos = require('./function/trigonometry/acos.js'); +exports.asin = require('./function/trigonometry/asin.js'); +exports.atan = require('./function/trigonometry/atan.js'); +exports.atan2 = require('./function/trigonometry/atan2.js'); +exports.cos = require('./function/trigonometry/cos.js'); +exports.cot = require('./function/trigonometry/cot.js'); +exports.csc = require('./function/trigonometry/csc.js'); +exports.sec = require('./function/trigonometry/sec.js'); +exports.sin = require('./function/trigonometry/sin.js'); +exports.tan = require('./function/trigonometry/tan.js'); + +// functions - units +exports['in'] = require('./function/units/in.js'); + +// functions - utils +exports.clone = require('./function/utils/clone.js'); +exports['eval'] = require('./function/utils/eval.js'); +exports.format = require('./function/utils/format.js'); +exports.help = require('./function/utils/help.js'); +exports['import'] = require('./function/utils/import.js'); +exports['typeof'] = require('./function/utils/typeof.js'); diff --git a/lib/exports.js b/lib/exports.js new file mode 100644 index 000000000..3e5226c69 --- /dev/null +++ b/lib/exports.js @@ -0,0 +1,30 @@ +/** + * CommonJS module exports + */ +if ((typeof module !== 'undefined') && (typeof module.exports !== 'undefined')) { + module.exports = math; +} +if (typeof exports !== 'undefined') { + exports = math; +} + +/** + * AMD module exports + */ +if (typeof(require) !== 'undefined' && typeof(define) !== 'undefined') { + define(function () { + return math; + }); +} + +/** + * Browser exports + */ +if (typeof(window) !== 'undefined') { + if (window['math']) { + object.deepExtend(window['math'], math); + } + else { + window['math'] = math; + } +} diff --git a/lib/expr/Parser.js b/lib/expr/Parser.js new file mode 100644 index 000000000..60f9c87cc --- /dev/null +++ b/lib/expr/Parser.js @@ -0,0 +1,122 @@ +var Scope = require('./Scope.js'); + +/** + * @constructor Parser + * Parser contains methods to evaluate or parse expressions, and has a number + * of convenience methods to get, set, and remove variables from memory. Parser + * keeps a scope containing variables in memory, which is used for all + * evaluations. + * + * Methods: + * var result = parser.eval(expr); // evaluate an expression + * var value = parser.get(name); // retrieve a variable from the parser + * parser.set(name, value); // set a variable in the parser + * parser.remove(name); // clear a variable from the + * // parsers scope + * parser.clear(); // clear the parsers scope + * + * // it is possible to parse an expression into a node tree: + * var node = parser.parse(expr); // parse an expression into a node tree + * var result = node.eval(); // evaluate a parsed node + * + * Example usage: + * var parser = new Parser(math); + * // Note: there is a convenience method which can be used instead: + * // var parser = new math.parser(); + * + * // evaluate expressions + * parser.eval('sqrt(3^2 + 4^2)'); // 5 + * parser.eval('sqrt(-4)'); // 2i + * parser.eval('2 inch in cm'); // 5.08 cm + * parser.eval('cos(45 deg)'); // 0.7071067811865476 + * + * // define variables and functions + * parser.eval('x = 7 / 2'); // 3.5 + * parser.eval('x + 3'); // 6.5 + * parser.eval('function f(x, y) = x^y'); // f(x, y) + * parser.eval('f(2, 3)'); // 8 + * + * // get and set variables and functions + * var x = parser.get('x'); // 7 + * var f = parser.get('f'); // function + * var g = f(3, 2); // 9 + * parser.set('h', 500); + * var i = parser.eval('h / 2'); // 250 + * parser.set('hello', function (name) { + * return 'hello, ' + name + '!'; + * }); + * parser.eval('hello("user")'); // "hello, user!" + * + * // clear defined functions and variables + * parser.clear(); + * + * + * @param {Object} math Link to the math.js namespace + */ +function Parser(math) { + if (!(this instanceof Parser)) { + throw new SyntaxError( + 'Parser constructor must be called with the new operator'); + } + + this.math = math; + this.scope = new Scope(math); +} + +/** + * Parse an expression end return the parsed function node. + * The node can be evaluated via node.eval() + * @param {String} expr + * @return {Node} node + * @throws {Error} + */ +Parser.prototype.parse = function (expr) { + return this.math.parse(expr, this.scope); +}; + +/** + * Parse and evaluate the given expression + * @param {String} expr A string containing an expression, for example "2+3" + * @return {*} result The result, or undefined when the expression was empty + * @throws {Error} + */ +Parser.prototype.eval = function (expr) { + var node = this.math.parse(expr, this.scope); + return node.eval(); +}; + +/** + * Get a variable (a function or variable) by name from the parsers scope. + * Returns undefined when not found + * @param {String} name + * @return {* | undefined} value + */ +Parser.prototype.get = function (name) { + return this.scope.get(name); +}; + +/** + * Set a symbol (a function or variable) by name from the parsers scope. + * @param {String} name + * @param {* | undefined} value + */ +Parser.prototype.set = function (name, value) { + this.scope.set(name, value); +}; + +/** + * Remove a variable from the parsers scope + * @param {String} name + */ +Parser.prototype.remove = function (name) { + this.scope.remove(name); +}; + +/** + * Clear the scope with variables and functions + */ +Parser.prototype.clear = function () { + this.scope.clear(); +}; + +module.exports = Parser; diff --git a/lib/expr/Scope.js b/lib/expr/Scope.js new file mode 100644 index 000000000..665eb2904 --- /dev/null +++ b/lib/expr/Scope.js @@ -0,0 +1,187 @@ +var Unit = require('../type/Unit.js'); + +/** + * Scope + * A scope stores values of symbols: variables and functions. + * + * Syntax: + * var scope = new Scope(math); + * var scope = new Scope(math, parentScope); + * var scope = new Scope(math, symbols); + * var scope = new Scope(math, parentScope, symbols); + * + * Where: + * {Object} math Link to the (static) math.js namespace + * {Scope | Object} parentScope Scope will be linked to a parent scope, + * which is traversed when resolving + * symbols. + * {Object} symbols A custom object that will be used to + * resolve and store variables. + * + * @constructor Scope + * @param {...} [math] + * @param {*} [arg1] + * @param {*} [arg2] + */ +function Scope(math, arg1, arg2) { + this.math = math; + + /** @type {Scope} */ + this.parentScope = null; + // TODO: rename parentScope to previousScope, add a nextScope, change Scope to a linked list node + + /** @type {Scope[]} */ + this.subScopes = null; + // TODO: rename subScopes to childScopes (or childNodes?) + + /** @type {Object.} */ + this.symbols = {}; // variables and functions + + /** @type {Object.} */ + this.cache = {}; // cache, referring to the scope.symbols object where + // a variable was last found + + // read second argument (can be parentScope or symbols map) + if (arg1) { + if (arg1 instanceof Scope) { + this.parentScope = arg1; + } + else if (arg1 instanceof Object) { + this.symbols = arg1; + } + } + + // read second argument (can be symbols map) + if (arg2) { + if (arg2 instanceof Object) { + this.symbols = arg2; + } + } +} + +Scope.prototype = { + /** + * Create a sub scope + * The variables in a sub scope are not accessible from the parent scope + * @return {Scope} subScope + */ + createSubScope: function () { + var subScope = new Scope(this.math, this); + if (!this.subScopes) { + this.subScopes = []; + } + this.subScopes.push(subScope); + return subScope; + }, + + /** + * Get a symbol value by name. + * Returns undefined if the symbol is not found in this scope or any of + * its parent scopes. + * @param {String} name + * @returns {* | undefined} value + */ + get: function (name) { + var value; + + // check itself + value = this.symbols[name]; + if (value !== undefined) { + return value; + } + + // read from cache + var symbols = this.cache[name]; + if (symbols) { + return symbols[name]; + } + + // check parent scope + var parent = this.parentScope; + while (parent) { + value = parent.symbols[name]; + if (value !== undefined) { + this.cache[name] = parent.symbols; + return value; + } + parent = parent.parentScope; + } + + // check static context + value = this.math[name]; + if (value !== undefined) { + this.cache[name] = this.math; + return value; + } + + // check if name is a unit + if (Unit.isPlainUnit(name)) { + value = new Unit(null, name); + this.cache[name] = {}; + this.cache[name][name] = value; + return value; + } + + return undefined; + }, + + /** + * Test whether this scope contains a symbol (will not check parent scopes) + * @param {String} name + * @return {Boolean} hasSymbol + */ + has: function (name) { + return (this.symbols[name] !== undefined); + }, + + /** + * Set a symbol value + * @param {String} name + * @param {*} value + * @return {*} value + */ + set: function (name, value) { + return this.symbols[name] = value; + }, + + /** + * Remove a symbol by name + * @param {String} name + */ + remove: function(name) { + delete this.symbols[name]; + }, + + /** + * Clear all symbols in this scope, its sub scopes, and clear the cache. + * Parent scopes will not be cleared. + */ + clear: function () { + var symbols = this.symbols; + for (var name in symbols) { + if (symbols.hasOwnProperty(name)) { + delete symbols[name]; + } + } + + if (this.subScopes) { + var subScopes = this.subScopes; + for (var i = 0, iMax = subScopes.length; i < iMax; i++) { + subScopes[i].clear(); + } + } + + this.clearCache(); + }, + + /** + * Clear cached links to symbols in other scopes + */ + clearCache: function () { + this.cache = {}; + } +}; + +Scope.context = []; // static context, for example the math namespace + +module.exports = Scope; diff --git a/lib/expr/Selector.js b/lib/expr/Selector.js new file mode 100644 index 000000000..330f5fada --- /dev/null +++ b/lib/expr/Selector.js @@ -0,0 +1,129 @@ +module.exports = function (math) { + var util = require('../util/index.js'), + string = util.string; + + /** + * @constructor Selector + * Wrap any value in a Selector, allowing to perform chained operations on + * the value. + * + * All methods available in the math.js library can be called upon the selector, + * and then will be evaluated with the value itself as first argument. + * The selector can be closed by executing selector.done(), which will return + * the final value. + * + * The Selector has a number of special functions: + * - done() Finalize the chained operation and return the selectors value. + * - valueOf() The same as done() + * - toString() Executes math.format() onto the selectors value, returning + * a string representation of the value. + * - get(...) Get a subset of the selectors value. Useful for example for + * matrices and arrays. + * - set(...) Replace a subset of the selectors value. Useful for example for + * matrices and arrays. + * + * @param {*} [value] + */ + function Selector (value) { + if (!(this instanceof Selector)) { + throw new SyntaxError( + 'Selector constructor must be called with the new operator'); + } + + if (value instanceof Selector) { + this.value = value.value; + } + else { + this.value = value; + } + } + + Selector.prototype = { + /** + * Close the selector. Returns the final value. + * Does the same as method valueOf() + * @returns {*} value + */ + done: function () { + return this.value; + }, + + /** + * Get a submatrix or subselection from current value. + * Only applicable when the current value has a method get. + */ + get: function (index) { + var value = this.value; + if (!value) { + throw Error('Selector value is undefined'); + } + + return new Selector(math.subset(value, index)); + }, + + /** + * Set a submatrix or subselection on current value. + * Only applicable when the current value has a method set. + */ + set: function (index, replacement) { + var value = this.value; + if (!value) { + throw Error('Selector value is undefined'); + } + + return new Selector(math.subset(value, index, replacement)); + }, + + /** + * Close the selector. Returns the final value. + * Does the same as method done() + * @returns {*} value + */ + valueOf: function () { + return this.value; + }, + + /** + * Get the string representation of the value in the selector + * @returns {String} + */ + toString: function () { + return string.format(this.value); + } + }; + + /** + * Create a proxy method for the selector + * @param {String} name + * @param {*} value The value or function to be proxied + */ + function createProxy(name, value) { + var slice = Array.prototype.slice; + if (typeof value === 'function') { + // a function + Selector.prototype[name] = function () { + var args = [this.value].concat(slice.call(arguments, 0)); + return new Selector(value.apply(this, args)); + } + } + else { + // a constant + Selector.prototype[name] = new Selector(value); + } + } + + Selector.createProxy = createProxy; + + /** + * initialise the Chain prototype with all functions and constants in math + */ + for (var prop in math) { + if (math.hasOwnProperty(prop) && prop) { + createProxy(prop, math[prop]); + } + } + + util.types.addType('selector', Selector); + + return Selector; +}; diff --git a/lib/expr/node/AssignmentNode.js b/lib/expr/node/AssignmentNode.js new file mode 100644 index 000000000..871fb5e79 --- /dev/null +++ b/lib/expr/node/AssignmentNode.js @@ -0,0 +1,63 @@ +var Node = require('./Node.js'); + +/** + * @constructor AssignmentNode + * Define a symbol, like "a = 3.2" + * + * @param {String} name Symbol name + * @param {Node} expr The expression defining the symbol + * @param {Scope} scope Scope to store the result + */ +function AssignmentNode(name, expr, scope) { + this.name = name; + this.expr = expr; + this.scope = scope; +} + +AssignmentNode.prototype = new Node(); + +/** + * Evaluate the assignment + * @return {*} result + */ +AssignmentNode.prototype.eval = function() { + if (this.expr === undefined) { + throw new Error('Undefined symbol ' + this.name); + } + + var result = this.expr.eval(); + this.scope.set(this.name, result); + + return result; +}; + +/** + * Find all nodes matching given filter + * @param {Object} filter See Node.find for a description of the filter options + * @returns {Node[]} nodes + */ +AssignmentNode.prototype.find = function (filter) { + var nodes = []; + + // check itself + if (this.match(filter)) { + nodes.push(this); + } + + // search in expression + if (this.expr) { + nodes = nodes.concat(this.expr.find(filter)); + } + + return nodes; +}; + +/** + * Get string representation + * @return {String} + */ +AssignmentNode.prototype.toString = function() { + return this.name + ' = ' + this.expr.toString(); +}; + +module.exports = AssignmentNode; \ No newline at end of file diff --git a/lib/expr/node/BlockNode.js b/lib/expr/node/BlockNode.js new file mode 100644 index 000000000..bdb1ec758 --- /dev/null +++ b/lib/expr/node/BlockNode.js @@ -0,0 +1,85 @@ +var Node = require('./Node.js'); + +/** + * @constructor BlockNode + * Holds a set with nodes + * @extends {Node} + */ +function BlockNode() { + this.params = []; + this.visible = []; +} + +BlockNode.prototype = new Node(); + +/** + * Add a parameter + * @param {Node} param + * @param {Boolean} [visible] true by default + */ +BlockNode.prototype.add = function (param, visible) { + var index = this.params.length; + this.params[index] = param; + this.visible[index] = (visible != undefined) ? visible : true; +}; + +/** + * Evaluate the set + * @return {*[]} results + * @override + */ +BlockNode.prototype.eval = function() { + // evaluate the parameters + var results = []; + for (var i = 0, iMax = this.params.length; i < iMax; i++) { + var result = this.params[i].eval(); + if (this.visible[i]) { + results.push(result); + } + } + + return results; +}; + +/** + * Find all nodes matching given filter + * @param {Object} filter See Node.find for a description of the filter options + * @returns {Node[]} nodes + */ +BlockNode.prototype.find = function (filter) { + var nodes = []; + + // check itself + if (this.match(filter)) { + nodes.push(this); + } + + // search in parameters + var params = this.params; + if (params) { + for (var i = 0, len = params.length; i < len; i++) { + nodes = nodes.concat(params[i].find(filter)); + } + } + + return nodes; +}; + +/** + * Get string representation + * @return {String} str + * @override + */ +BlockNode.prototype.toString = function() { + var strings = []; + + for (var i = 0, iMax = this.params.length; i < iMax; i++) { + if (this.visible[i]) { + strings.push('\n ' + this.params[i].toString()); + } + } + + return '[' + strings.join(',') + '\n]'; +}; + +module.exports = BlockNode; diff --git a/lib/expr/node/ConstantNode.js b/lib/expr/node/ConstantNode.js new file mode 100644 index 000000000..e82d36580 --- /dev/null +++ b/lib/expr/node/ConstantNode.js @@ -0,0 +1,31 @@ +var Node = require('./Node.js'), + string = require('../../util/string.js'); + +/** + * @constructor ConstantNode + * @param {*} value + * @extends {Node} + */ +function ConstantNode(value) { + this.value = value; +} + +ConstantNode.prototype = new Node(); + +/** + * Evaluate the constant (just return it) + * @return {*} value + */ +ConstantNode.prototype.eval = function () { + return this.value; +}; + +/** + * Get string representation + * @return {String} str + */ +ConstantNode.prototype.toString = function() { + return string.format(this.value); +}; + +module.exports = ConstantNode; diff --git a/lib/expr/node/FunctionNode.js b/lib/expr/node/FunctionNode.js new file mode 100644 index 000000000..dad2400db --- /dev/null +++ b/lib/expr/node/FunctionNode.js @@ -0,0 +1,87 @@ +var Node = require('./Node.js'), + error = require('../../util/error.js'); + +/** + * @constructor FunctionNode + * Function assignment + * + * @param {String} name Function name + * @param {String[]} variables Variable names + * @param {Node} expr The function expression + * @param {Scope} functionScope Scope in which to write variable values + * @param {Scope} scope Scope to store the resulting function assignment + */ +function FunctionNode(name, variables, expr, functionScope, scope) { + this.name = name; + this.variables = variables; + this.expr = expr; + this.scope = scope; + + // create function + this.fn = function () { + var num = variables ? variables.length : 0; + + // validate correct number of arguments + if (arguments.length != num) { + throw new error.ArgumentsError(name, arguments.length, num); + } + + // fill in the provided arguments in the functionScope variables + for (var i = 0; i < num; i++) { + functionScope.set(variables[i], arguments[i]); + } + + // evaluate the expression + return expr.eval(); + }; + + this.fn.toString = function() { + // TODO: what to return as toString? + return name + '(' + variables.join(', ') + ')'; + //return name + '(' + variableNames.join(', ') + ') = ' + expr.toString(); + }; +} + +FunctionNode.prototype = new Node(); + +/** + * Evaluate the function assignment + * @return {function} fn + */ +FunctionNode.prototype.eval = function() { + // put the definition in the scope + this.scope.set(this.name, this.fn); + + return this.fn; +}; + +/** + * Find all nodes matching given filter + * @param {Object} filter See Node.find for a description of the filter options + * @returns {Node[]} nodes + */ +FunctionNode.prototype.find = function (filter) { + var nodes = []; + + // check itself + if (this.match(filter)) { + nodes.push(this); + } + + // search in expression + if (this.expr) { + nodes = nodes.concat(this.expr.find(filter)); + } + + return nodes; +}; + +/** + * get string representation + * @return {String} str + */ +FunctionNode.prototype.toString = function() { + return this.fn.toString(); +}; + +module.exports = FunctionNode; diff --git a/lib/expr/node/MatrixNode.js b/lib/expr/node/MatrixNode.js new file mode 100644 index 000000000..612f33d57 --- /dev/null +++ b/lib/expr/node/MatrixNode.js @@ -0,0 +1,155 @@ +var Node = require('./Node.js'), + object = require('../../util/object.js'), + string = require('../../util/string.js'), + collection = require('../../type/collection.js'), + Matrix = require('../../type/Matrix.js'), + Range = require('../../type/Range.js'); + +/** + * @constructor MatrixNode + * Holds an 2-dimensional array with nodes + * @param {Array[]} nodes 2 dimensional array with nodes + * @extends {Node} + */ +function MatrixNode(nodes) { + this.nodes = nodes || []; +} + +MatrixNode.prototype = new Node(); + +/** + * Evaluate the array + * @return {Matrix} results + * @override + */ +MatrixNode.prototype.eval = function() { + // evaluate all nodes in the 2d array, and merge the results into a matrix + var nodes = this.nodes, + results = [], + mergeNeeded = false; + + for (var r = 0, rows = nodes.length; r < rows; r++) { + var nodes_r = nodes[r]; + var results_r = []; + for (var c = 0, cols = nodes_r.length; c < cols; c++) { + var results_rc = nodes_r[c].eval(); + if (collection.isCollection(results_rc)) { + mergeNeeded = true; + } + results_r[c] = results_rc; + } + results[r] = results_r; + } + + if (mergeNeeded) { + results = merge(results); + } + + return new Matrix(results); +}; + +/** + * Find all nodes matching given filter + * @param {Object} filter See Node.find for a description of the filter options + * @returns {Node[]} nodes + */ +MatrixNode.prototype.find = function (filter) { + var results = []; + + // check itself + if (this.match(filter)) { + results.push(this); + } + + // search in all nodes + var nodes = this.nodes; + for (var r = 0, rows = nodes.length; r < rows; r++) { + var nodes_r = nodes[r]; + for (var c = 0, cols = nodes_r.length; c < cols; c++) { + results = results.concat(nodes_r[c].find(filter)); + } + } + + return results; +}; + +/** + * Merge nested Matrices in a two dimensional Array. + * @param {Array} array Two-dimensional array containing Matrices + * @return {Array} merged The merged array (two-dimensional) + */ +function merge (array) { + var merged = []; + var rows = array.length; + for (var r = 0; r < rows; r++) { + var array_r = array[r]; + var cols = array_r.length; + var submatrix = null; + var submatrixRows = null; + for (var c = 0; c < cols; c++) { + var entry = object.clone(array_r[c]); + var size; + if (entry instanceof Matrix) { + // get the data from the matrix + size = entry.size(); + entry = entry.valueOf(); + if (size.length == 1) { + entry = [entry]; + size = [1, size[0]]; + } + else if (size.length > 2) { + throw new Error('Cannot merge a multi dimensional matrix'); + } + } + else if (entry instanceof Range) { + // change range into an 1xn matrix + entry = [entry.valueOf()]; + size = [1, entry[0].length]; + } + else if (Array.isArray(entry)) { + // change array into a 1xn matrix + size = [1, entry.length]; + entry = [entry]; + } + else { + // change scalar into a 1x1 matrix + size = [1, 1]; + entry = [[entry]]; + } + + // check the height of this row + if (submatrix == null) { + // first entry + submatrix = entry; + submatrixRows = size[0]; + } + else if (size[0] == submatrixRows) { + // merge + for (var s = 0; s < submatrixRows; s++) { + submatrix[s] = submatrix[s].concat(entry[s]); + } + } + else { + // no good... + throw new Error('Dimension mismatch ' + + '(' + size[0] + ' != ' + submatrixRows + ')'); + } + } + + // merge the submatrix + merged = merged.concat(submatrix); + } + + return merged; +} + +/** + * Get string representation + * @return {String} str + * @override + */ +MatrixNode.prototype.toString = function() { + return string.format(this.nodes); +}; + +module.exports = MatrixNode; diff --git a/lib/expr/node/Node.js b/lib/expr/node/Node.js new file mode 100644 index 000000000..12182c083 --- /dev/null +++ b/lib/expr/node/Node.js @@ -0,0 +1,71 @@ +/** + * Node + */ +function Node() {} + +/** + * Evaluate the node + * @return {*} result + */ +Node.prototype.eval = function () { + throw new Error('Cannot evaluate a Node interface'); +}; + +/** + * Find any node in the node tree matching given filter. For example, to + * find all nodes of type SymbolNode having name 'x': + * + * var results = Node.find({ + * type: SymbolNode, + * properties: { + * name: 'x' + * } + * }); + * + * @param {Object} filter Available parameters: + * {Function} type + * {Object} properties + * @return {Node[]} nodes An array with nodes matching given filter criteria + */ +Node.prototype.find = function (filter) { + return this.match(filter) ? [this] : []; +}; + +/** + * Test if this object matches given filter + * @param {Object} filter Available parameters: + * {Function} type + * {Object} properties + * @return {Boolean} matches True if there is a match + */ +Node.prototype.match = function (filter) { + var match = true; + + if (filter) { + if (filter.type && !(this instanceof filter.type)) { + match = false; + } + if (match && filter.properties) { + for (var prop in filter.properties) { + if (filter.properties.hasOwnProperty(prop)) { + if (this[prop] != filter.properties[prop]) { + match = false; + break; + } + } + } + } + } + + return match; +}; + +/** + * Get string representation + * @return {String} + */ +Node.prototype.toString = function() { + return ''; +}; + +module.exports = Node; diff --git a/lib/expr/node/OperatorNode.js b/lib/expr/node/OperatorNode.js new file mode 100644 index 000000000..6b851056d --- /dev/null +++ b/lib/expr/node/OperatorNode.js @@ -0,0 +1,86 @@ +var Node = require('./Node.js'); + +/** + * @constructor OperatorNode + * An operator with two arguments, like 2+3 + * @param {String} name Function name, for example '+' + * @param {function} fn Function, for example math.add + * @param {Node[]} params Parameters + */ +function OperatorNode (name, fn, params) { + this.name = name; + this.fn = fn; + this.params = params; +} + +OperatorNode.prototype = new Node(); + +/** + * Evaluate the parameters + * @return {*} result + */ +OperatorNode.prototype.eval = function() { + return this.fn.apply(this, this.params.map(function (param) { + return param.eval(); + })); +}; + +/** + * Find all nodes matching given filter + * @param {Object} filter See Node.find for a description of the filter options + * @returns {Node[]} nodes + */ +OperatorNode.prototype.find = function (filter) { + var nodes = []; + + // check itself + if (this.match(filter)) { + nodes.push(this); + } + + // search in parameters + var params = this.params; + if (params) { + for (var i = 0, len = params.length; i < len; i++) { + nodes = nodes.concat(params[i].find(filter)); + } + } + + return nodes; +}; + +/** + * Get string representation + * @return {String} str + */ +OperatorNode.prototype.toString = function() { + var params = this.params; + + switch (params.length) { + case 1: + if (this.name == '-') { + // special case: unary minus + return '-' + params[0].toString(); + } + else { + // for example '5!' + return params[0].toString() + this.name; + } + + case 2: // for example '2+3' + var lhs = params[0].toString(); + if (params[0] instanceof OperatorNode) { + lhs = '(' + lhs + ')'; + } + var rhs = params[1].toString(); + if (params[1] instanceof OperatorNode) { + rhs = '(' + rhs + ')'; + } + return lhs + ' ' + this.name + ' ' + rhs; + + default: // this should occur. format as a function call + return this.name + '(' + this.params.join(', ') + ')'; + } +}; + +module.exports = OperatorNode; diff --git a/lib/expr/node/ParamsNode.js b/lib/expr/node/ParamsNode.js new file mode 100644 index 000000000..e0fc0f990 --- /dev/null +++ b/lib/expr/node/ParamsNode.js @@ -0,0 +1,129 @@ +var Node = require('./Node.js'), + SymbolNode = require('./SymbolNode.js').SymbolNode; + +/** + * @constructor ParamsNode + * invoke a list with parameters on the results of a node + * @param {Object} math The math namespace containing all functions + * @param {Node} object + * @param {Node[]} params + * @param {Scope[]} paramScopes A scope for every parameter, where the + * index variable 'end' can be defined. + */ +function ParamsNode (math, object, params, paramScopes) { + this.math = math; + + this.object = object; + this.params = params; + this.paramScopes = paramScopes; + + // check whether any of the params expressions uses the context symbol 'end' + this.hasContextParams = false; + if (params) { + var filter = { + type: SymbolNode, + properties: { + name: 'end' + } + }; + + for (var i = 0, len = params.length; i < len; i++) { + if (params[i].find(filter).length > 0) { + this.hasContextParams = true; + break; + } + } + } +} + +ParamsNode.prototype = new Node(); + +/** + * Evaluate the parameters + * @return {*} result + */ +ParamsNode.prototype.eval = function() { + var i, len; + + // evaluate the object + var object = this.object; + if (object == undefined) { + throw new Error ('Node undefined'); + } + var obj = object.eval(); + + // evaluate the values of context parameter 'end' when needed + if (this.hasContextParams) { + var paramScopes = this.paramScopes, + size = this.math.size(obj).valueOf(); + + if (paramScopes && size) { + for (i = 0, len = this.params.length; i < len; i++) { + var paramScope = paramScopes[i]; + if (paramScope) { + paramScope.set('end', size[i]); + } + } + } + } + + // evaluate the parameters + var params = this.params, + results = []; + for (i = 0, len = this.params.length; i < len; i++) { + results[i] = params[i].eval(); + } + + if (typeof obj === 'function') { + // invoke a function with the parameters + return obj.apply(this, results); + } + else { + // get a subset of the object + return this.math.subset(obj, results); + } +}; + +/** + * Find all nodes matching given filter + * @param {Object} filter See Node.find for a description of the filter options + * @returns {Node[]} nodes + */ +ParamsNode.prototype.find = function (filter) { + var nodes = []; + + // check itself + if (this.match(filter)) { + nodes.push(this); + } + + // search object + if (this.object) { + nodes = nodes.concat(this.object.find(filter)); + } + + // search in parameters + var params = this.params; + if (params) { + for (var i = 0, len = params.length; i < len; i++) { + nodes = nodes.concat(params[i].find(filter)); + } + } + + return nodes; +}; + +/** + * Get string representation + * @return {String} str + */ +ParamsNode.prototype.toString = function() { + // format the parameters like "(2, 4.2)" + var str = this.object ? this.object.toString() : ''; + if (this.params) { + str += '(' + this.params.join(', ') + ')'; + } + return str; +}; + +module.exports = ParamsNode; diff --git a/lib/expr/node/SymbolNode.js b/lib/expr/node/SymbolNode.js new file mode 100644 index 000000000..ed1dfeaa8 --- /dev/null +++ b/lib/expr/node/SymbolNode.js @@ -0,0 +1,42 @@ +var Node = require('./Node.js'); + +/** + * @constructor SymbolNode + * A symbol node can hold and resolve a symbol + * @param {String} name + * @param {Scope} scope + * @extends {Node} + */ +function SymbolNode(name, scope) { + this.name = name; + this.scope = scope; +} + +SymbolNode.prototype = new Node(); + +/** + * Evaluate the symbol. Throws an error when the symbol is undefined. + * @return {*} result + * @override + */ +SymbolNode.prototype.eval = function() { + // return the value of the symbol + var value = this.scope.get(this.name); + + if (value === undefined) { + throw new Error('Undefined symbol ' + this.name); + } + + return value; +}; + +/** + * Get string representation + * @return {String} str + * @override + */ +SymbolNode.prototype.toString = function() { + return this.name; +}; + +module.exports = SymbolNode; diff --git a/lib/expr/node/UpdateNode.js b/lib/expr/node/UpdateNode.js new file mode 100644 index 000000000..c0fb3c3e7 --- /dev/null +++ b/lib/expr/node/UpdateNode.js @@ -0,0 +1,137 @@ +var Node = require('./Node.js'), + SymbolNode = require('./SymbolNode.js').SymbolNode; + +/** + * @constructor UpdateNode + * Update a symbol value, like a(2,3) = 4.5 + * + * @param {Object} math The math namespace containing all functions + * @param {String} name Symbol name + * @param {Node[] | undefined} params One or more parameters + * @param {Scope[]} paramScopes A scope for every parameter, where the + * index variable 'end' can be defined. + * @param {Node} expr The expression defining the symbol + * @param {Scope} scope Scope to store the result + */ +function UpdateNode(math, name, params, paramScopes, expr, scope) { + this.math = math; + + this.name = name; + this.params = params; + this.paramScopes = paramScopes; + this.expr = expr; + this.scope = scope; + + // check whether any of the params expressions uses the context symbol 'end' + this.hasContextParams = false; + var filter = { + type: SymbolNode, + properties: { + name: 'end' + } + }; + for (var i = 0, len = params.length; i < len; i++) { + if (params[i].find(filter).length > 0) { + this.hasContextParams = true; + break; + } + } +} + +UpdateNode.prototype = new Node(); + +/** + * Evaluate the assignment + * @return {*} result + */ +UpdateNode.prototype.eval = function() { + if (this.expr === undefined) { + throw new Error('Undefined symbol ' + this.name); + } + + var result; + + // test if definition is currently undefined + var prevResult = this.scope.get(this.name); + if (prevResult == undefined) { + throw new Error('Undefined symbol ' + this.name); + } + + // evaluate the values of context parameter 'end' when needed + if (this.hasContextParams) { + var paramScopes = this.paramScopes, + size = this.math.size(prevResult).valueOf(); + + if (paramScopes && size) { + for (var i = 0, len = this.params.length; i < len; i++) { + var paramScope = paramScopes[i]; + if (paramScope) { + paramScope.set('end', size[i]); + } + } + } + } + + // change part of a matrix, for example "a=[]", "a(2,3)=4.5" + var paramResults = []; + this.params.forEach(function (param) { + paramResults.push(param.eval()); + }); + + var exprResult = this.expr.eval(); + + // replace subset + result = this.math.subset(prevResult, paramResults, exprResult); + + this.scope.set(this.name, result); + + return result; +}; + +/** + * Find all nodes matching given filter + * @param {Object} filter See Node.find for a description of the filter options + * @returns {Node[]} nodes + */ +UpdateNode.prototype.find = function (filter) { + var nodes = []; + + // check itself + if (this.match(filter)) { + nodes.push(this); + } + + // search in parameters + var params = this.params; + if (params) { + for (var i = 0, len = params.length; i < len; i++) { + nodes = nodes.concat(params[i].find(filter)); + } + } + + // search in expression + if (this.expr) { + nodes = nodes.concat(this.expr.find(filter)); + } + + return nodes; +}; + +/** + * Get string representation + * @return {String} + */ +UpdateNode.prototype.toString = function() { + var str = ''; + + str += this.name; + if (this.params && this.params.length) { + str += '(' + this.params.join(', ') + ')'; + } + str += ' = '; + str += this.expr.toString(); + + return str; +}; + +module.exports = UpdateNode; diff --git a/lib/expr/node/handlers.js b/lib/expr/node/handlers.js new file mode 100644 index 000000000..d28776282 --- /dev/null +++ b/lib/expr/node/handlers.js @@ -0,0 +1,4 @@ +/** + * Custom node handlers, + * (can be added to the exports object) + */ diff --git a/lib/expr/node/index.js b/lib/expr/node/index.js new file mode 100644 index 000000000..68ffd9bd5 --- /dev/null +++ b/lib/expr/node/index.js @@ -0,0 +1,12 @@ +exports.AssignmentNode = require('./AssignmentNode.js'); +exports.BlockNode = require('./BlockNode.js'); +exports.ConstantNode = require('./ConstantNode.js'); +exports.FunctionNode = require('./FunctionNode.js'); +exports.MatrixNode = require('./MatrixNode.js'); +exports.Node = require('./Node.js'); +exports.OperatorNode = require('./OperatorNode.js'); +exports.ParamsNode = require('./ParamsNode.js'); +exports.SymbolNode = require('./SymbolNode.js'); +exports.UpdateNode = require('./UpdateNode.js'); + +exports.handlers = require('./handlers.js'); diff --git a/lib/function/arithmetic/abs.js b/lib/function/arithmetic/abs.js new file mode 100644 index 000000000..a83587f0e --- /dev/null +++ b/lib/function/arithmetic/abs.js @@ -0,0 +1,46 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Complex = require('../../type/Complex.js'), + Matrix = require('../../type/Matrix.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isCollection = collection.isCollection; + + /** + * Calculate the absolute value of a value. + * + * abs(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + */ + math.abs = function abs(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('abs', arguments.length, 1); + } + + if (isNumber(x)) { + return Math.abs(x); + } + + if (isComplex(x)) { + return Math.sqrt(x.re * x.re + x.im * x.im); + } + + if (isCollection(x)) { + return collection.map(x, abs); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return abs(x.valueOf()); + } + + throw new util.error.UnsupportedTypeError('abs', x); + }; +}; diff --git a/lib/function/arithmetic/add.js b/lib/function/arithmetic/add.js new file mode 100644 index 000000000..ab28653bf --- /dev/null +++ b/lib/function/arithmetic/add.js @@ -0,0 +1,97 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Complex = require('../../type/Complex.js'), + Matrix = require('../../type/Matrix.js'), + Unit = require('../../type/Unit.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isString = util.string.isString, + isComplex = Complex.isComplex, + isUnit = Unit.isUnit, + isCollection = collection.isCollection; + + /** + * Add two values + * + * x + y + * add(x, y) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Unit | String | Array | Matrix} x + * @param {Number | Complex | Unit | String | Array | Matrix} y + * @return {Number | Complex | Unit | String | Array | Matrix} res + */ + math.add = function add(x, y) { + if (arguments.length != 2) { + throw new util.error.ArgumentsError('add', arguments.length, 2); + } + + if (isNumber(x)) { + if (isNumber(y)) { + // number + number + return x + y; + } + else if (isComplex(y)) { + // number + complex + return Complex.create( + x + y.re, + y.im + ) + } + } + else if (isComplex(x)) { + if (isNumber(y)) { + // complex + number + return Complex.create( + x.re + y, + x.im + ) + } + else if (isComplex(y)) { + // complex + complex + return Complex.create( + x.re + y.re, + x.im + y.im + ); + } + } + else if (isUnit(x)) { + if (isUnit(y)) { + if (!x.equalBase(y)) { + throw new Error('Units do not match'); + } + + if (x.value == null) { + throw new Error('Unit on left hand side of operator + has an undefined value'); + } + + if (y.value == null) { + throw new Error('Unit on right hand side of operator + has an undefined value'); + } + + var res = x.clone(); + res.value += y.value; + res.fixPrefix = false; + return res; + } + } + + if (isString(x) || isString(y)) { + return x + y; + } + + if (isCollection(x) || isCollection(y)) { + return collection.map2(x, y, add); + } + + if (x.valueOf() !== x || y.valueOf() !== y) { + // fallback on the objects primitive value + return add(x.valueOf(), y.valueOf()); + } + + throw new util.error.UnsupportedTypeError('add', x, y); + }; +}; diff --git a/lib/function/arithmetic/ceil.js b/lib/function/arithmetic/ceil.js new file mode 100644 index 000000000..469335a24 --- /dev/null +++ b/lib/function/arithmetic/ceil.js @@ -0,0 +1,48 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Complex = require('../../type/Complex.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isCollection =collection.isCollection, + isComplex = Complex.isComplex; + + /** + * Round a value towards plus infinity + * + * ceil(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + */ + math.ceil = function ceil(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('ceil', arguments.length, 1); + } + + if (isNumber(x)) { + return Math.ceil(x); + } + + if (isComplex(x)) { + return Complex.create ( + Math.ceil(x.re), + Math.ceil(x.im) + ); + } + + if (isCollection(x)) { + return collection.map(x, ceil); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return ceil(x.valueOf()); + } + + throw new util.error.UnsupportedTypeError('ceil', x); + }; +}; diff --git a/lib/function/arithmetic/cube.js b/lib/function/arithmetic/cube.js new file mode 100644 index 000000000..8bccce8f7 --- /dev/null +++ b/lib/function/arithmetic/cube.js @@ -0,0 +1,46 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Complex = require('../../type/Complex.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isCollection = collection.isCollection; + + /** + * Compute the cube of a value + * + * x .* x .* x + * cube(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + */ + math.cube = function cube(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('cube', arguments.length, 1); + } + + if (isNumber(x)) { + return x * x * x; + } + + if (isComplex(x)) { + return math.multiply(math.multiply(x, x), x); + } + + if (isCollection(x)) { + return collection.map(x, cube); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return cube(x.valueOf()); + } + + throw new util.error.UnsupportedTypeError('cube', x); + }; +}; diff --git a/lib/function/arithmetic/divide.js b/lib/function/arithmetic/divide.js new file mode 100644 index 000000000..66b5ef11f --- /dev/null +++ b/lib/function/arithmetic/divide.js @@ -0,0 +1,109 @@ +module.exports = function(math) { + var util = require('../../util/index.js'), + + Complex = require('../../type/Complex.js'), + Matrix = require('../../type/Matrix.js'), + Unit = require('../../type/Unit.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isUnit = Unit.isUnit, + isCollection = collection.isCollection; + + /** + * Divide two values. + * + * x / y + * divide(x, y) + * + * @param {Number | Complex | Unit | Array | Matrix} x + * @param {Number | Complex} y + * @return {Number | Complex | Unit | Array | Matrix} res + */ + math.divide = function divide(x, y) { + if (arguments.length != 2) { + throw new util.error.ArgumentsError('divide', arguments.length, 2); + } + + if (isNumber(x)) { + if (isNumber(y)) { + // number / number + return x / y; + } + else if (isComplex(y)) { + // number / complex + return _divideComplex(new Complex(x, 0), y); + } + } + + if (isComplex(x)) { + if (isNumber(y)) { + // complex / number + return _divideComplex(x, new Complex(y, 0)); + } + else if (isComplex(y)) { + // complex / complex + return _divideComplex(x, y); + } + } + + if (isUnit(x)) { + if (isNumber(y)) { + var res = x.clone(); + res.value /= y; + return res; + } + } + + if (isCollection(x)) { + if (isCollection(y)) { + // TODO: implement matrix right division using pseudo inverse + // http://www.mathworks.nl/help/matlab/ref/mrdivide.html + // http://www.gnu.org/software/octave/doc/interpreter/Arithmetic-Ops.html + // http://stackoverflow.com/questions/12263932/how-does-gnu-octave-matrix-division-work-getting-unexpected-behaviour + return math.multiply(x, math.inv(y)); + } + else { + // matrix / scalar + return collection.map2(x, y, divide); + } + } + + if (isCollection(y)) { + // TODO: implement matrix right division using pseudo inverse + return math.multiply(x, math.inv(y)); + } + + if (x.valueOf() !== x || y.valueOf() !== y) { + // fallback on the objects primitive value + return divide(x.valueOf(), y.valueOf()); + } + + throw new util.error.UnsupportedTypeError('divide', x, y); + }; + + /** + * Divide two complex numbers. x / y or divide(x, y) + * @param {Complex} x + * @param {Complex} y + * @return {Complex} res + * @private + */ + function _divideComplex (x, y) { + var den = y.re * y.re + y.im * y.im; + if (den != 0) { + return Complex.create( + (x.re * y.re + x.im * y.im) / den, + (x.im * y.re - x.re * y.im) / den + ); + } + else { + // both y.re and y.im are zero + return Complex.create( + (x.re != 0) ? (x.re / 0) : 0, + (x.im != 0) ? (x.im / 0) : 0 + ); + } + } +}; diff --git a/lib/function/arithmetic/edivide.js b/lib/function/arithmetic/edivide.js new file mode 100644 index 000000000..dcd763b62 --- /dev/null +++ b/lib/function/arithmetic/edivide.js @@ -0,0 +1,22 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + collection = require('../../type/collection.js'); + + /** + * Divide two values element wise. + * + * x ./ y + * edivide(x, y) + * + * @param {Number | Complex | Unit | Array | Matrix} x + * @param {Number | Complex | Unit | Array | Matrix} y + * @return {Number | Complex | Unit | Array | Matrix} res + */ + math.edivide = function edivide(x, y) { + if (arguments.length != 2) { + throw new util.error.ArgumentsError('edivide', arguments.length, 2); + } + + return collection.deepMap2(x, y, math.divide); + }; +}; diff --git a/lib/function/arithmetic/emultiply.js b/lib/function/arithmetic/emultiply.js new file mode 100644 index 000000000..559fa65e9 --- /dev/null +++ b/lib/function/arithmetic/emultiply.js @@ -0,0 +1,22 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + collection = require('../../type/collection.js'); + + /** + * Multiply two values element wise. + * + * x .* y + * emultiply(x, y) + * + * @param {Number | Complex | Unit | Array | Matrix} x + * @param {Number | Complex | Unit | Array | Matrix} y + * @return {Number | Complex | Unit | Array | Matrix} res + */ + math.emultiply = function emultiply(x, y) { + if (arguments.length != 2) { + throw new util.error.ArgumentsError('emultiply', arguments.length, 2); + } + + return collection.deepMap2(x, y, math.multiply); + }; +}; diff --git a/lib/function/arithmetic/epow.js b/lib/function/arithmetic/epow.js new file mode 100644 index 000000000..59990bfc3 --- /dev/null +++ b/lib/function/arithmetic/epow.js @@ -0,0 +1,22 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + collection = require('../../type/collection.js'); + + /** + * Calculates the power of x to y element wise + * + * x .^ y + * epow(x, y) + * + * @param {Number | Complex | Unit | Array | Matrix} x + * @param {Number | Complex | Unit | Array | Matrix} y + * @return {Number | Complex | Unit | Array | Matrix} res + */ + math.epow = function epow(x, y) { + if (arguments.length != 2) { + throw new util.error.ArgumentsError('epow', arguments.length, 2); + } + + return collection.deepMap2(x, y, math.pow); + }; +}; diff --git a/lib/function/arithmetic/equal.js b/lib/function/arithmetic/equal.js new file mode 100644 index 000000000..a6c152d35 --- /dev/null +++ b/lib/function/arithmetic/equal.js @@ -0,0 +1,71 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Complex = require('../../type/Complex.js'), + Unit = require('../../type/Unit.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isString = util.string.isString, + isComplex = Complex.isComplex, + isUnit = Unit.isUnit, + isCollection = collection.isCollection; + + /** + * Check if value x equals y, + * + * x == y + * equal(x, y) + * + * For matrices, the function is evaluated element wise. + * In case of complex numbers, x.re must equal y.re, and x.im must equal y.im. + * + * @param {Number | Complex | Unit | String | Array | Matrix} x + * @param {Number | Complex | Unit | String | Array | Matrix} y + * @return {Boolean | Array | Matrix} res + */ + math.equal = function equal(x, y) { + if (arguments.length != 2) { + throw new util.error.ArgumentsError('equal', arguments.length, 2); + } + + if (isNumber(x)) { + if (isNumber(y)) { + return x == y; + } + else if (isComplex(y)) { + return (x == y.re) && (y.im == 0); + } + } + if (isComplex(x)) { + if (isNumber(y)) { + return (x.re == y) && (x.im == 0); + } + else if (isComplex(y)) { + return (x.re == y.re) && (x.im == y.im); + } + } + + if ((isUnit(x)) && (isUnit(y))) { + if (!x.equalBase(y)) { + throw new Error('Cannot compare units with different base'); + } + return x.value == y.value; + } + + if (isString(x) || isString(y)) { + return x == y; + } + + if (isCollection(x) || isCollection(y)) { + return collection.map2(x, y, equal); + } + + if (x.valueOf() !== x || y.valueOf() !== y) { + // fallback on the objects primitive values + return equal(x.valueOf(), y.valueOf()); + } + + throw new util.error.UnsupportedTypeError('equal', x, y); + }; +}; diff --git a/lib/function/arithmetic/exp.js b/lib/function/arithmetic/exp.js new file mode 100644 index 000000000..9bf1a6a69 --- /dev/null +++ b/lib/function/arithmetic/exp.js @@ -0,0 +1,49 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Complex = require('../../type/Complex.js'), + Matrix = require('../../type/Matrix.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isCollection = collection.isCollection; + + /** + * Calculate the exponent of a value + * + * exp(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + */ + math.exp = function exp (x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('exp', arguments.length, 1); + } + + if (isNumber(x)) { + return Math.exp(x); + } + if (isComplex(x)) { + var r = Math.exp(x.re); + return Complex.create( + r * Math.cos(x.im), + r * Math.sin(x.im) + ); + } + + if (isCollection(x)) { + return collection.map(x, exp); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return exp(x.valueOf()); + } + + throw new util.error.UnsupportedTypeError('exp', x); + }; +}; diff --git a/lib/function/arithmetic/fix.js b/lib/function/arithmetic/fix.js new file mode 100644 index 000000000..c586aeaa5 --- /dev/null +++ b/lib/function/arithmetic/fix.js @@ -0,0 +1,48 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Complex = require('../../type/Complex.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isCollection = collection.isCollection; + + /** + * Round a value towards zero + * + * fix(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + */ + math.fix = function fix(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('fix', arguments.length, 1); + } + + if (isNumber(x)) { + return (x > 0) ? Math.floor(x) : Math.ceil(x); + } + + if (isComplex(x)) { + return Complex.create( + (x.re > 0) ? Math.floor(x.re) : Math.ceil(x.re), + (x.im > 0) ? Math.floor(x.im) : Math.ceil(x.im) + ); + } + + if (isCollection(x)) { + return collection.map(x, fix); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return fix(x.valueOf()); + } + + throw new util.error.UnsupportedTypeError('fix', x); + }; +}; diff --git a/lib/function/arithmetic/floor.js b/lib/function/arithmetic/floor.js new file mode 100644 index 000000000..92281c133 --- /dev/null +++ b/lib/function/arithmetic/floor.js @@ -0,0 +1,48 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Complex = require('../../type/Complex.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isCollection = collection.isCollection; + + /** + * Round a value towards minus infinity + * + * floor(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + */ + math.floor = function floor(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('floor', arguments.length, 1); + } + + if (isNumber(x)) { + return Math.floor(x); + } + + if (isComplex(x)) { + return Complex.create ( + Math.floor(x.re), + Math.floor(x.im) + ); + } + + if (isCollection(x)) { + return collection.map(x, floor); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return floor(x.valueOf()); + } + + throw new util.error.UnsupportedTypeError('floor', x); + }; +}; diff --git a/lib/function/arithmetic/gcd.js b/lib/function/arithmetic/gcd.js new file mode 100644 index 000000000..90093cb85 --- /dev/null +++ b/lib/function/arithmetic/gcd.js @@ -0,0 +1,66 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isInteger = util.number.isInteger, + isCollection = collection.isCollection; + + /** + * Calculate the greatest common divisor for two or more values or arrays. + * + * gcd(a, b) + * gcd(a, b, c, ...) + * + * For matrices, the function is evaluated element wise. + * + * @param {... Number | Array | Matrix} args two or more integer numbers + * @return {Number | Array | Matrix} greatest common divisor + */ + math.gcd = function gcd(args) { + var a = arguments[0], + b = arguments[1], + t; + + if (arguments.length == 2) { + // two arguments + if (isNumber(a) && isNumber(b)) { + if (!isInteger(a) || !isInteger(b)) { + throw new Error('Parameters in function gcd must be integer numbers'); + } + + // http://en.wikipedia.org/wiki/Euclidean_algorithm + while (b != 0) { + t = b; + b = a % t; + a = t; + } + return Math.abs(a); + } + + // evaluate gcd element wise + if (isCollection(a) || isCollection(b)) { + return collection.map2(a, b, gcd); + } + + if (a.valueOf() !== a || b.valueOf() !== b) { + // fallback on the objects primitive value + return gcd(a.valueOf(), b.valueOf()); + } + + throw new util.error.UnsupportedTypeError('gcd', a, b); + } + + if (arguments.length > 2) { + // multiple arguments. Evaluate them iteratively + for (var i = 1; i < arguments.length; i++) { + a = gcd(a, arguments[i]); + } + return a; + } + + // zero or one argument + throw new SyntaxError('Function gcd expects two or more arguments'); + }; +}; diff --git a/lib/function/arithmetic/larger.js b/lib/function/arithmetic/larger.js new file mode 100644 index 000000000..6c478059d --- /dev/null +++ b/lib/function/arithmetic/larger.js @@ -0,0 +1,71 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Complex = require('../../type/Complex.js'), + Unit = require('../../type/Unit.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isString = util.string.isString, + isComplex = Complex.isComplex, + isUnit = Unit.isUnit, + isCollection = collection.isCollection; + + /** + * Check if value x is larger y + * + * x > y + * larger(x, y) + * + * For matrices, the function is evaluated element wise. + * In case of complex numbers, the absolute values of a and b are compared. + * + * @param {Number | Complex | Unit | String | Array | Matrix} x + * @param {Number | Complex | Unit | String | Array | Matrix} y + * @return {Boolean | Array | Matrix} res + */ + math.larger = function larger(x, y) { + if (arguments.length != 2) { + throw new util.error.ArgumentsError('larger', arguments.length, 2); + } + + if (isNumber(x)) { + if (isNumber(y)) { + return x > y; + } + else if (isComplex(y)) { + return x > math.abs(y); + } + } + if (isComplex(x)) { + if (isNumber(y)) { + return math.abs(x) > y; + } + else if (isComplex(y)) { + return math.abs(x) > math.abs(y); + } + } + + if ((isUnit(x)) && (isUnit(y))) { + if (!x.equalBase(y)) { + throw new Error('Cannot compare units with different base'); + } + return x.value > y.value; + } + + if (isString(x) || isString(y)) { + return x > y; + } + + if (isCollection(x) || isCollection(y)) { + return collection.map2(x, y, larger); + } + + if (x.valueOf() !== x || y.valueOf() !== y) { + // fallback on the objects primitive values + return larger(x.valueOf(), y.valueOf()); + } + + throw new util.error.UnsupportedTypeError('larger', x, y); + }; +}; diff --git a/lib/function/arithmetic/largereq.js b/lib/function/arithmetic/largereq.js new file mode 100644 index 000000000..da721adc5 --- /dev/null +++ b/lib/function/arithmetic/largereq.js @@ -0,0 +1,71 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Complex = require('../../type/Complex.js'), + Unit = require('../../type/Unit.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isString = util.string.isString, + isComplex = Complex.isComplex, + isUnit = Unit.isUnit, + isCollection = collection.isCollection; + + /** + * Check if value x is larger or equal to y + * + * x >= y + * largereq(x, y) + * + * For matrices, the function is evaluated element wise. + * In case of complex numbers, the absolute values of a and b are compared. + * + * @param {Number | Complex | Unit | String | Array | Matrix} x + * @param {Number | Complex | Unit | String | Array | Matrix} y + * @return {Boolean | Array | Matrix} res + */ + math.largereq = function largereq(x, y) { + if (arguments.length != 2) { + throw new util.error.ArgumentsError('largereq', arguments.length, 2); + } + + if (isNumber(x)) { + if (isNumber(y)) { + return x >= y; + } + else if (isComplex(y)) { + return x >= math.abs(y); + } + } + if (isComplex(x)) { + if (isNumber(y)) { + return math.abs(x) >= y; + } + else if (isComplex(y)) { + return math.abs(x) >= math.abs(y); + } + } + + if ((isUnit(x)) && (isUnit(y))) { + if (!x.equalBase(y)) { + throw new Error('Cannot compare units with different base'); + } + return x.value >= y.value; + } + + if (isString(x) || isString(y)) { + return x >= y; + } + + if (isCollection(x) || isCollection(y)) { + return collection.map2(x, y, largereq); + } + + if (x.valueOf() !== x || y.valueOf() !== y) { + // fallback on the objects primitive values + return largereq(x.valueOf(), y.valueOf()); + } + + throw new util.error.UnsupportedTypeError('largereq', x, y); + }; +}; diff --git a/lib/function/arithmetic/lcm.js b/lib/function/arithmetic/lcm.js new file mode 100644 index 000000000..ad885821d --- /dev/null +++ b/lib/function/arithmetic/lcm.js @@ -0,0 +1,71 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isInteger = util.number.isInteger, + isCollection = collection.isCollection; + + /** + * Calculate the least common multiple for two or more values or arrays. + * + * lcm(a, b) + * lcm(a, b, c, ...) + * + * lcm is defined as: + * lcm(a, b) = abs(a * b) / gcd(a, b) + * + * For matrices, the function is evaluated element wise. + * + * @param {... Number | Array | Matrix} args two or more integer numbers + * @return {Number | Array | Matrix} least common multiple + */ + math.lcm = function lcm(args) { + var a = arguments[0], + b = arguments[1], + t; + + if (arguments.length == 2) { + // two arguments + if (isNumber(a) && isNumber(b)) { + if (!isInteger(a) || !isInteger(b)) { + throw new Error('Parameters in function lcm must be integer numbers'); + } + + // http://en.wikipedia.org/wiki/Euclidean_algorithm + // evaluate gcd here inline to reduce overhead + var prod = a * b; + while (b != 0) { + t = b; + b = a % t; + a = t; + } + return Math.abs(prod / a); + } + + // evaluate lcm element wise + if (isCollection(a) || isCollection(b)) { + return collection.map2(a, b, lcm); + } + + if (a.valueOf() !== a || b.valueOf() !== b) { + // fallback on the objects primitive value + return lcm(a.valueOf(), b.valueOf()); + } + + throw new util.error.UnsupportedTypeError('lcm', a, b); + } + + if (arguments.length > 2) { + // multiple arguments. Evaluate them iteratively + for (var i = 1; i < arguments.length; i++) { + a = lcm(a, arguments[i]); + } + return a; + } + + // zero or one argument + throw new SyntaxError('Function lcm expects two or more arguments'); + }; +}; diff --git a/lib/function/arithmetic/log.js b/lib/function/arithmetic/log.js new file mode 100644 index 000000000..0f9c0e2ab --- /dev/null +++ b/lib/function/arithmetic/log.js @@ -0,0 +1,63 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Complex = require('../../type/Complex.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isCollection = collection.isCollection; + + /** + * Calculate the logarithm of a value + * + * log(x) + * log(x, base) + * + * base is optional. If not provided, the natural logarithm of x is calculated. + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Array | Matrix} x + * @param {Number | Complex} [base] + * @return {Number | Complex | Array | Matrix} res + */ + math.log = function log(x, base) { + if (arguments.length == 1) { + // calculate natural logarithm, log(x) + if (isNumber(x)) { + if (x >= 0) { + return Math.log(x); + } + else { + // negative value -> complex value computation + return log(new Complex(x, 0)); + } + } + + if (isComplex(x)) { + return Complex.create ( + Math.log(Math.sqrt(x.re * x.re + x.im * x.im)), + Math.atan2(x.im, x.re) + ); + } + + if (isCollection(x)) { + return collection.map(x, log); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive values + return log(x.valueOf()); + } + + throw new util.error.UnsupportedTypeError('log', x); + } + else if (arguments.length == 2) { + // calculate logarithm for a specified base, log(x, base) + return math.divide(log(x), log(base)); + } + else { + throw new util.error.ArgumentsError('log', arguments.length, 1, 2); + } + }; +}; diff --git a/lib/function/arithmetic/log10.js b/lib/function/arithmetic/log10.js new file mode 100644 index 000000000..c4a7a8633 --- /dev/null +++ b/lib/function/arithmetic/log10.js @@ -0,0 +1,54 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Complex = require('../../type/Complex.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isCollection = collection.isCollection; + + /** + * Calculate the 10-base logarithm of a value + * + * log10(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + */ + math.log10 = function log10(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('log10', arguments.length, 1); + } + + if (isNumber(x)) { + if (x >= 0) { + return Math.log(x) / Math.LN10; + } + else { + // negative value -> complex value computation + return log10(new Complex(x, 0)); + } + } + + if (isComplex(x)) { + return Complex.create ( + Math.log(Math.sqrt(x.re * x.re + x.im * x.im)) / Math.LN10, + Math.atan2(x.im, x.re) / Math.LN10 + ); + } + + if (isCollection(x)) { + return collection.map(x, log10); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return log10(x.valueOf()); + } + + throw new util.error.UnsupportedTypeError('log10', x); + }; +}; diff --git a/lib/function/arithmetic/mod.js b/lib/function/arithmetic/mod.js new file mode 100644 index 000000000..7cd64a090 --- /dev/null +++ b/lib/function/arithmetic/mod.js @@ -0,0 +1,74 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isCollection = collection.isCollection; + + /** + * Calculates the modulus, the remainder of an integer division. + * + * x % y + * mod(x, y) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Array | Matrix} x + * @param {Number | Array | Matrix} y + * @return {Number | Array | Matrix} res + */ + math.mod = function mod(x, y) { + if (arguments.length != 2) { + throw new util.error.ArgumentsError('mod', arguments.length, 2); + } + + // see http://functions.wolfram.com/IntegerFunctions/Mod/ + + if (isNumber(x) && isNumber(y)) { + // number % number + return _mod(x, y); + } + + // TODO: implement mod for complex values + + if (isCollection(x) || isCollection(y)) { + return collection.map2(x, y, mod); + } + + if (x.valueOf() !== x || y.valueOf() !== y) { + // fallback on the objects primitive values + return mod(x.valueOf(), y.valueOf()); + } + + throw new util.error.UnsupportedTypeError('mod', x, y); + }; + + /** + * Calculate the modulus of two numbers + * @param {Number} x + * @param {Number} y + * @returns {number} res + * @private + */ + function _mod(x, y) { + if (y > 0) { + if (x > 0) { + return x % y; + } + else if (x == 0) { + return 0; + } + else { // x < 0 + return x - y * Math.floor(x / y); + } + } + else if (y == 0) { + return x; + } + else { // y < 0 + // TODO: implement mod for a negative divisor + throw new Error('Cannot calculate mod for a negative divisor'); + } + } +}; diff --git a/lib/function/arithmetic/multiply.js b/lib/function/arithmetic/multiply.js new file mode 100644 index 000000000..2fc270cf4 --- /dev/null +++ b/lib/function/arithmetic/multiply.js @@ -0,0 +1,210 @@ +module.exports = function(math) { + var util = require('../../util/index.js'), + + Complex = require('../../type/Complex.js'), + Matrix = require('../../type/Matrix.js'), + Unit = require('../../type/Unit.js'), + collection = require('../../type/collection.js'), + + array = util.array, + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isArray = Array.isArray, + isUnit = Unit.isUnit; + + /** + * Multiply two values. + * + * x * y + * multiply(x, y) + * + * @param {Number | Complex | Unit | Array | Matrix} x + * @param {Number | Complex | Unit | Array | Matrix} y + * @return {Number | Complex | Unit | Array | Matrix} res + */ + math.multiply = function multiply(x, y) { + if (arguments.length != 2) { + throw new util.error.ArgumentsError('multiply', arguments.length, 2); + } + + if (isNumber(x)) { + if (isNumber(y)) { + // number * number + return x * y; + } + else if (isComplex(y)) { + // number * complex + return _multiplyComplex (new Complex(x, 0), y); + } + else if (isUnit(y)) { + res = y.clone(); + res.value *= x; + return res; + } + } + else if (isComplex(x)) { + if (isNumber(y)) { + // complex * number + return _multiplyComplex (x, new Complex(y, 0)); + } + else if (isComplex(y)) { + // complex * complex + return _multiplyComplex (x, y); + } + } + else if (isUnit(x)) { + if (isNumber(y)) { + res = x.clone(); + res.value *= y; + return res; + } + } + else if (isArray(x)) { + if (isArray(y)) { + // matrix * matrix + var sizeX = array.size(x); + var sizeY = array.size(y); + + if (sizeX.length != 2) { + throw new Error('Can only multiply a 2 dimensional matrix ' + + '(A has ' + sizeX.length + ' dimensions)'); + } + if (sizeY.length != 2) { + throw new Error('Can only multiply a 2 dimensional matrix ' + + '(B has ' + sizeY.length + ' dimensions)'); + } + if (sizeX[1] != sizeY[0]) { + throw new RangeError('Dimensions mismatch in multiplication. ' + + 'Columns of A must match rows of B ' + + '(A is ' + sizeX[0] + 'x' + sizeX[1] + + ', B is ' + sizeY[0] + 'x' + sizeY[1] + ', ' + + sizeY[1] + ' != ' + sizeY[0] + ')'); + } + + // TODO: performance of matrix multiplication can be improved + var res = [], + rows = sizeX[0], + cols = sizeY[1], + num = sizeX[1]; + for (var r = 0; r < rows; r++) { + res[r] = []; + for (var c = 0; c < cols; c++) { + var result = null; + for (var n = 0; n < num; n++) { + var p = multiply(x[r][n], y[n][c]); + result = (result == null) ? p : math.add(result, p); + } + res[r][c] = result; + } + } + + return res; + } + else if (y instanceof Matrix) { + return new Matrix(multiply(x.valueOf(), y.valueOf())); + } + else { + // matrix * scalar + return collection.map2(x, y, multiply); + } + } + else if (x instanceof Matrix) { + return new Matrix(multiply(x.valueOf(), y.valueOf())); + } + + if (isArray(y)) { + // scalar * matrix + return collection.map2(x, y, multiply); + } + else if (y instanceof Matrix) { + return new Matrix(multiply(x.valueOf(), y.valueOf())); + } + + if (x.valueOf() !== x || y.valueOf() !== y) { + // fallback on the objects primitive values + return multiply(x.valueOf(), y.valueOf()); + } + + throw new util.error.UnsupportedTypeError('multiply', x, y); + }; + + /** + * Multiply two complex numbers. x * y or multiply(x, y) + * @param {Complex} x + * @param {Complex} y + * @return {Complex | Number} res + * @private + */ + function _multiplyComplex (x, y) { + // Note: we test whether x or y are pure real or pure complex, + // to prevent unnecessary NaN values. For example, Infinity*i should + // result in Infinity*i, and not in NaN+Infinity*i + + if (x.im == 0) { + // x is pure real + if (y.im == 0) { + // y is pure real + return x.re * y.re; + } + else if (y.re == 0) { + // y is pure complex + return new Complex( + 0, + x.re * y.im + ); + } + else { + // y has a real and complex part + return new Complex( + x.re * y.re, + x.re * y.im + ); + } + } + else if (x.re == 0) { + // x is pure complex + if (y.im == 0) { + // y is pure real + return new Complex( + 0, + x.im * y.re + ); + } + else if (y.re == 0) { + // y is pure complex + return -x.im * y.im; + } + else { + // y has a real and complex part + return new Complex( + -x.im * y.im, + x.im * y.re + ); + } + } + else { + // x has a real and complex part + if (y.im == 0) { + // y is pure real + return new Complex( + x.re * y.re, + x.im * y.re + ); + } + else if (y.re == 0) { + // y is pure complex + return new Complex( + -x.im * y.im, + x.re * y.im + ); + } + else { + // y has a real and complex part + return new Complex( + x.re * y.re - x.im * y.im, + x.re * y.im + x.im * y.re + ); + } + } + } +}; diff --git a/lib/function/arithmetic/pow.js b/lib/function/arithmetic/pow.js new file mode 100644 index 000000000..d045d19b4 --- /dev/null +++ b/lib/function/arithmetic/pow.js @@ -0,0 +1,105 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Complex = require('../../type/Complex.js'), + Matrix = require('../../type/Matrix.js'), + + array = util.array, + isNumber = util.number.isNumber, + isArray = Array.isArray, + isInteger = util.number.isInteger, + isComplex = Complex.isComplex; + + /** + * Calculates the power of x to y + * + * x ^ y + * pow(x, y) + * + * @param {Number | Complex | Array | Matrix} x + * @param {Number | Complex} y + * @return {Number | Complex | Array | Matrix} res + */ + math.pow = function pow(x, y) { + if (arguments.length != 2) { + throw new util.error.ArgumentsError('pow', arguments.length, 2); + } + + if (isNumber(x)) { + if (isNumber(y)) { + if (isInteger(y) || x >= 0) { + // real value computation + return Math.pow(x, y); + } + else { + return powComplex(new Complex(x, 0), new Complex(y, 0)); + } + } + else if (isComplex(y)) { + return powComplex(new Complex(x, 0), y); + } + } + else if (isComplex(x)) { + if (isNumber(y)) { + return powComplex(x, new Complex(y, 0)); + } + else if (isComplex(y)) { + return powComplex(x, y); + } + } + else if (isArray(x)) { + if (!isNumber(y) || !isInteger(y) || y < 0) { + throw new TypeError('For A^b, b must be a positive integer ' + + '(value is ' + y + ')'); + } + // verify that A is a 2 dimensional square matrix + var s = array.size(x); + if (s.length != 2) { + throw new Error('For A^b, A must be 2 dimensional ' + + '(A has ' + s.length + ' dimensions)'); + } + if (s[0] != s[1]) { + throw new Error('For A^b, A must be square ' + + '(size is ' + s[0] + 'x' + s[1] + ')'); + } + + if (y == 0) { + // return the identity matrix + return math.eye(s[0]); + } + else { + // value > 0 + var res = x; + for (var i = 1; i < y; i++) { + res = math.multiply(x, res); + } + return res; + } + } + else if (x instanceof Matrix) { + return new Matrix(pow(x.valueOf(), y)); + } + + if (x.valueOf() !== x || y.valueOf() !== y) { + // fallback on the objects primitive values + return pow(x.valueOf(), y.valueOf()); + } + + throw new util.error.UnsupportedTypeError('pow', x, y); + }; + + /** + * Calculates the power of x to y, x^y, for two complex numbers. + * @param {Complex} x + * @param {Complex} y + * @return {Complex} res + * @private + */ + function powComplex (x, y) { + // complex computation + // x^y = exp(log(x)*y) = exp((abs(x)+i*arg(x))*y) + var temp1 = math.log(x); + var temp2 = math.multiply(temp1, y); + return math.exp(temp2); + } +}; diff --git a/lib/function/arithmetic/round.js b/lib/function/arithmetic/round.js new file mode 100644 index 000000000..aba4759c0 --- /dev/null +++ b/lib/function/arithmetic/round.js @@ -0,0 +1,104 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Complex = require('../../type/Complex.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isCollection = collection.isCollection; + + /** + * Round a value towards the nearest integer + * + * round(x) + * round(x, n) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Array | Matrix} x + * @param {Number | Array} [n] number of decimals (by default n=0) + * @return {Number | Complex | Array | Matrix} res + */ + math.round = function round(x, n) { + if (arguments.length != 1 && arguments.length != 2) { + throw new util.error.ArgumentsError('round', arguments.length, 1, 2); + } + + if (n == undefined) { + // round (x) + if (isNumber(x)) { + return Math.round(x); + } + + if (isComplex(x)) { + return Complex.create ( + Math.round(x.re), + Math.round(x.im) + ); + } + + if (isCollection(x)) { + return collection.map(x, round); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return round(x.valueOf()); + } + + throw new util.error.UnsupportedTypeError('round', x); + } + else { + // round (x, n) + if (!isNumber(n)) { + throw new TypeError('Number of decimals in function round must be an integer'); + } + if (n !== Math.round(n)) { + throw new TypeError('Number of decimals in function round must be integer'); + } + if (n < 0 || n > 9) { + throw new Error ('Number of decimals in function round must be in te range of 0-9'); + } + + if (isNumber(x)) { + return roundNumber(x, n); + } + + if (isComplex(x)) { + return Complex.create ( + roundNumber(x.re, n), + roundNumber(x.im, n) + ); + } + + if (isCollection(x) || isCollection(n)) { + return collection.map2(x, n, round); + } + + if (x.valueOf() !== x || n.valueOf() !== n) { + // fallback on the objects primitive values + return round(x.valueOf(), n.valueOf()); + } + + throw new util.error.UnsupportedTypeError('round', x, n); + } + }; + + /** + * round a number to the given number of decimals, or to zero if decimals is + * not provided + * @param {Number} value + * @param {Number} [decimals] number of decimals, between 0 and 15 (0 by default) + * @return {Number} roundedValue + */ + function roundNumber (value, decimals) { + if (decimals) { + var p = Math.pow(10, decimals); + return Math.round(value * p) / p; + } + else { + return Math.round(value); + } + } +}; diff --git a/lib/function/arithmetic/sign.js b/lib/function/arithmetic/sign.js new file mode 100644 index 000000000..d2630eb72 --- /dev/null +++ b/lib/function/arithmetic/sign.js @@ -0,0 +1,48 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Complex = require('../../type/Complex.js'), + collection = require('../../type/collection.js'), + + number = util.number, + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isCollection = collection.isCollection; + + /** + * Compute the sign of a value. + * + * sign(x) + * + * The sign of a value x is 1 when x > 1, -1 when x < 0, and 0 when x == 0 + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + */ + math.sign = function sign(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('sign', arguments.length, 1); + } + + if (isNumber(x)) { + return number.sign(x); + } + + if (isComplex(x)) { + var abs = Math.sqrt(x.re * x.re + x.im * x.im); + return Complex.create(x.re / abs, x.im / abs); + } + + if (isCollection(x)) { + return collection.map(x, sign); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return sign(x.valueOf()); + } + + throw new util.error.UnsupportedTypeError('sign', x); + }; +}; diff --git a/lib/function/arithmetic/smaller.js b/lib/function/arithmetic/smaller.js new file mode 100644 index 000000000..76143cf70 --- /dev/null +++ b/lib/function/arithmetic/smaller.js @@ -0,0 +1,71 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Complex = require('../../type/Complex.js'), + Unit = require('../../type/Unit.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isString = util.string.isString, + isComplex = Complex.isComplex, + isUnit = Unit.isUnit, + isCollection = collection.isCollection; + + /** + * Check if value x is smaller y + * + * x < y + * smaller(x, y) + * + * For matrices, the function is evaluated element wise. + * In case of complex numbers, the absolute values of a and b are compared. + * + * @param {Number | Complex | Unit | String | Array | Matrix} x + * @param {Number | Complex | Unit | String | Array | Matrix} y + * @return {Boolean | Array | Matrix} res + */ + math.smaller = function smaller(x, y) { + if (arguments.length != 2) { + throw new util.error.ArgumentsError('smaller', arguments.length, 2); + } + + if (isNumber(x)) { + if (isNumber(y)) { + return x < y; + } + else if (isComplex(y)) { + return x < math.abs(y); + } + } + if (isComplex(x)) { + if (isNumber(y)) { + return math.abs(x) < y; + } + else if (isComplex(y)) { + return math.abs(x) < math.abs(y); + } + } + + if ((isUnit(x)) && (isUnit(y))) { + if (!x.equalBase(y)) { + throw new Error('Cannot compare units with different base'); + } + return x.value < y.value; + } + + if (isString(x) || isString(y)) { + return x < y; + } + + if (isCollection(x) || isCollection(y)) { + return collection.map2(x, y, smaller); + } + + if (x.valueOf() !== x || y.valueOf() !== y) { + // fallback on the objects primitive values + return smaller(x.valueOf(), y.valueOf()); + } + + throw new util.error.UnsupportedTypeError('smaller', x, y); + }; +}; diff --git a/lib/function/arithmetic/smallereq.js b/lib/function/arithmetic/smallereq.js new file mode 100644 index 000000000..c45f3e6ce --- /dev/null +++ b/lib/function/arithmetic/smallereq.js @@ -0,0 +1,71 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Complex = require('../../type/Complex.js'), + Unit = require('../../type/Unit.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isString = util.string.isString, + isComplex = Complex.isComplex, + isUnit = Unit.isUnit, + isCollection = collection.isCollection; + + /** + * Check if value a is smaller or equal to b + * + * a <= b + * smallereq(a, b) + * + * For matrices, the function is evaluated element wise. + * In case of complex numbers, the absolute values of a and b are compared. + * + * @param {Number | Complex | Unit | String | Array | Matrix} x + * @param {Number | Complex | Unit | String | Array | Matrix} y + * @return {Boolean | Array | Matrix} res + */ + math.smallereq = function smallereq(x, y) { + if (arguments.length != 2) { + throw new util.error.ArgumentsError('smallereq', arguments.length, 2); + } + + if (isNumber(x)) { + if (isNumber(y)) { + return x <= y; + } + else if (isComplex(y)) { + return x <= math.abs(y); + } + } + if (isComplex(x)) { + if (isNumber(y)) { + return math.abs(x) <= y; + } + else if (isComplex(y)) { + return math.abs(x) <= math.abs(y); + } + } + + if ((isUnit(x)) && (isUnit(y))) { + if (!x.equalBase(y)) { + throw new Error('Cannot compare units with different base'); + } + return x.value <= y.value; + } + + if (isString(x) || isString(y)) { + return x <= y; + } + + if (isCollection(x) || isCollection(y)) { + return collection.map2(x, y, smallereq); + } + + if (x.valueOf() !== x || y.valueOf() !== y) { + // fallback on the objects primitive values + return smallereq(x.valueOf(), y.valueOf()); + } + + throw new util.error.UnsupportedTypeError('smallereq', x, y); + }; +}; diff --git a/lib/function/arithmetic/sqrt.js b/lib/function/arithmetic/sqrt.js new file mode 100644 index 000000000..b3448fcae --- /dev/null +++ b/lib/function/arithmetic/sqrt.js @@ -0,0 +1,62 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Complex = require('../../type/Complex.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isCollection = collection.isCollection; + + /** + * Calculate the square root of a value + * + * sqrt(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + */ + math.sqrt = function sqrt (x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('sqrt', arguments.length, 1); + } + + if (isNumber(x)) { + if (x >= 0) { + return Math.sqrt(x); + } + else { + return sqrt(new Complex(x, 0)); + } + } + + if (isComplex(x)) { + var r = Math.sqrt(x.re * x.re + x.im * x.im); + if (x.im >= 0) { + return Complex.create( + 0.5 * Math.sqrt(2.0 * (r + x.re)), + 0.5 * Math.sqrt(2.0 * (r - x.re)) + ); + } + else { + return Complex.create( + 0.5 * Math.sqrt(2.0 * (r + x.re)), + -0.5 * Math.sqrt(2.0 * (r - x.re)) + ); + } + } + + if (isCollection(x)) { + return collection.map(x, sqrt); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return sqrt(x.valueOf()); + } + + throw new util.error.UnsupportedTypeError('sqrt', x); + }; +}; diff --git a/lib/function/arithmetic/square.js b/lib/function/arithmetic/square.js new file mode 100644 index 000000000..7debfc6f4 --- /dev/null +++ b/lib/function/arithmetic/square.js @@ -0,0 +1,46 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Complex = require('../../type/Complex.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isCollection = collection.isCollection; + + /** + * Compute the square of a value + * + * x .* x + * square(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + */ + math.square = function square(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('square', arguments.length, 1); + } + + if (isNumber(x)) { + return x * x; + } + + if (isComplex(x)) { + return math.multiply(x, x); + } + + if (isCollection(x)) { + return collection.map(x, square); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return square(x.valueOf()); + } + + throw new util.error.UnsupportedTypeError('square', x); + }; +}; diff --git a/lib/function/arithmetic/subtract.js b/lib/function/arithmetic/subtract.js new file mode 100644 index 000000000..989e808b1 --- /dev/null +++ b/lib/function/arithmetic/subtract.js @@ -0,0 +1,94 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Complex = require('../../type/Complex.js'), + Matrix = require('../../type/Matrix.js'), + Unit = require('../../type/Unit.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isString = util.string.isString, + isComplex = Complex.isComplex, + isUnit = Unit.isUnit, + isCollection = collection.isCollection; + + /** + * Subtract two values + * + * x - y + * subtract(x, y) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Unit | Array | Matrix} x + * @param {Number | Complex | Unit | Array | Matrix} y + * @return {Number | Complex | Unit | Array | Matrix} res + */ + math.subtract = function subtract(x, y) { + if (arguments.length != 2) { + throw new util.error.ArgumentsError('subtract', arguments.length, 2); + } + + if (isNumber(x)) { + if (isNumber(y)) { + // number - number + return x - y; + } + else if (isComplex(y)) { + // number - complex + return Complex.create ( + x - y.re, + - y.im + ); + } + } + else if (isComplex(x)) { + if (isNumber(y)) { + // complex - number + return Complex.create ( + x.re - y, + x.im + ) + } + else if (isComplex(y)) { + // complex - complex + return Complex.create ( + x.re - y.re, + x.im - y.im + ) + } + } + else if (isUnit(x)) { + if (isUnit(y)) { + if (!x.equalBase(y)) { + throw new Error('Units do not match'); + } + + if (x.value == null) { + throw new Error('Unit on left hand side of operator - has an undefined value'); + } + + if (y.value == null) { + throw new Error('Unit on right hand side of operator - has an undefined value'); + } + + var res = x.clone(); + res.value -= y.value; + res.fixPrefix = false; + + return res; + } + } + + if (isCollection(x) || isCollection(y)) { + return collection.map2(x, y, subtract); + } + + if (x.valueOf() !== x || y.valueOf() !== y) { + // fallback on the objects primitive values + return subtract(x.valueOf(), y.valueOf()); + } + + throw new util.error.UnsupportedTypeError('subtract', x, y); + }; +}; diff --git a/lib/function/arithmetic/unary.js b/lib/function/arithmetic/unary.js new file mode 100644 index 000000000..0375aebab --- /dev/null +++ b/lib/function/arithmetic/unary.js @@ -0,0 +1,55 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Complex = require('../../type/Complex.js'), + Unit = require('../../type/Unit.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isUnit = Unit.isUnit, + isCollection = collection.isCollection; + + /** + * Inverse the sign of a value. + * + * -x + * unary(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Unit | Array | Matrix} x + * @return {Number | Complex | Unit | Array | Matrix} res + */ + math.unary = function unary(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('unary', arguments.length, 1); + } + + if (isNumber(x)) { + return -x; + } + else if (isComplex(x)) { + return Complex.create( + -x.re, + -x.im + ); + } + else if (isUnit(x)) { + var res = x.clone(); + res.value = -x.value; + return res; + } + + if (isCollection(x)) { + return collection.map(x, unary); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return unary(x.valueOf()); + } + + throw new util.error.UnsupportedTypeError('unary', x); + }; +}; diff --git a/lib/function/arithmetic/unequal.js b/lib/function/arithmetic/unequal.js new file mode 100644 index 000000000..39b828b4f --- /dev/null +++ b/lib/function/arithmetic/unequal.js @@ -0,0 +1,66 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Complex = require('../../type/Complex.js'), + Unit = require('../../type/Unit.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isString = util.string.isString, + isComplex = Complex.isComplex, + isUnit = Unit.isUnit, + isCollection = collection.isCollection; + + /** + * Check if value x unequals y, x != y + * In case of complex numbers, x.re must unequal y.re, or x.im must unequal y.im + * @param {Number | Complex | Unit | String | Array | Matrix | Range} x + * @param {Number | Complex | Unit | String | Array | Matrix | Range} y + * @return {Boolean | Array | Matrix} res + */ + math.unequal = function unequal(x, y) { + if (arguments.length != 2) { + throw new util.error.ArgumentsError('unequal', arguments.length, 2); + } + + if (isNumber(x)) { + if (isNumber(y)) { + return x != y; + } + else if (isComplex(y)) { + return (x != y.re) || (y.im != 0); + } + } + + if (isComplex(x)) { + if (isNumber(y)) { + return (x.re != y) || (x.im != 0); + } + else if (isComplex(y)) { + return (x.re != y.re) || (x.im != y.im); + } + } + + if ((isUnit(x)) && (isUnit(y))) { + if (!x.equalBase(y)) { + throw new Error('Cannot compare units with different base'); + } + return x.value != y.value; + } + + if (isString(x) || isString(y)) { + return x != y; + } + + if (isCollection(x) || isCollection(y)) { + return collection.map2(x, y, unequal); + } + + if (x.valueOf() !== x || y.valueOf() !== y) { + // fallback on the objects primitive values + return unequal(x.valueOf(), y.valueOf()); + } + + throw new util.error.UnsupportedTypeError('unequal', x, y); + }; +}; diff --git a/lib/function/arithmetic/xgcd.js b/lib/function/arithmetic/xgcd.js new file mode 100644 index 000000000..906b0b9a7 --- /dev/null +++ b/lib/function/arithmetic/xgcd.js @@ -0,0 +1,45 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + isNumber = util.number.isNumber, + isInteger = util.number.isInteger; + + /** + * Calculate the extended greatest common divisor for two values. + * + * xgcd(a, b) + * + * @param {Number} a An integer number + * @param {Number} b An integer number + * @return {Array} An array containing 3 integers [div, m, n] + * where div = gcd(a, b) and a*m + b*n = div + * + * @see http://en.wikipedia.org/wiki/Extended_Euclidean_algorithm + */ + math.xgcd = function xgcd(a, b) { + if (arguments.length == 2) { + // two arguments + if (isNumber(a) && isNumber(b)) { + if (!isInteger(a) || !isInteger(b)) { + throw new Error('Parameters in function xgcd must be integer numbers'); + } + + if(b == 0) { + return [a, 1, 0]; + } + + var tmp = xgcd(b, a % b), + div = tmp[0], + x = tmp[1], + y = tmp[2]; + + return [div, y, x - y * Math.floor(a / b)]; + } + + throw new util.error.UnsupportedTypeError('xgcd', a, b); + } + + // zero or one argument + throw new SyntaxError('Function xgcd expects two arguments'); + }; +}; diff --git a/lib/function/complex/arg.js b/lib/function/complex/arg.js new file mode 100644 index 000000000..a7bd691ff --- /dev/null +++ b/lib/function/complex/arg.js @@ -0,0 +1,47 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Complex = require('../../type/Complex.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isCollection =collection.isCollection, + isComplex = Complex.isComplex; + + /** + * Compute the argument of a complex value. + * If x = a + bi, the argument is computed as atan2(b, a). + * + * arg(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Array | Matrix} x + * @return {Number | Array | Matrix} res + */ + math.arg = function arg(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('arg', arguments.length, 1); + } + + if (isNumber(x)) { + return Math.atan2(0, x); + } + + if (isComplex(x)) { + return Math.atan2(x.im, x.re); + } + + if (isCollection(x)) { + return collection.map(x, arg); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return arg(x.valueOf()); + } + + // handle other types just as non-complex values + return math.atan2(0, x); + }; +}; diff --git a/lib/function/complex/conj.js b/lib/function/complex/conj.js new file mode 100644 index 000000000..5790e1444 --- /dev/null +++ b/lib/function/complex/conj.js @@ -0,0 +1,48 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Complex = require('../../type/Complex.js'), + collection = require('../../type/collection.js'), + + object = util.object, + isNumber = util.number.isNumber, + isCollection =collection.isCollection, + isComplex = Complex.isComplex; + + /** + * Compute the complex conjugate of a complex value. + * If x = a+bi, the complex conjugate is a-bi. + * + * conj(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + */ + math.conj = function conj(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('conj', arguments.length, 1); + } + + if (isNumber(x)) { + return x; + } + + if (isComplex(x)) { + return Complex.create(x.re, -x.im); + } + + if (isCollection(x)) { + return collection.map(x, conj); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return conj(x.valueOf()); + } + + // return a clone of the value for non-complex values + return object.clone(x); + }; +}; diff --git a/lib/function/complex/im.js b/lib/function/complex/im.js new file mode 100644 index 000000000..9ce9aa552 --- /dev/null +++ b/lib/function/complex/im.js @@ -0,0 +1,46 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Complex = require('../../type/Complex.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isCollection =collection.isCollection, + isComplex = Complex.isComplex; + + /** + * Get the imaginary part of a complex number. + * + * im(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Array | Matrix} x + * @return {Number | Array | Matrix} im + */ + math.im = function im(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('im', arguments.length, 1); + } + + if (isNumber(x)) { + return 0; + } + + if (isComplex(x)) { + return x.im; + } + + if (isCollection(x)) { + return collection.map(x, im); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return im(x.valueOf()); + } + + // return 0 for all non-complex values + return 0; + }; +}; diff --git a/lib/function/complex/re.js b/lib/function/complex/re.js new file mode 100644 index 000000000..1b26b49d4 --- /dev/null +++ b/lib/function/complex/re.js @@ -0,0 +1,47 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Complex = require('../../type/Complex.js'), + collection = require('../../type/collection.js'), + + object = util.object, + isNumber = util.number.isNumber, + isCollection =collection.isCollection, + isComplex = Complex.isComplex; + + /** + * Get the real part of a complex number. + * + * re(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Array | Matrix} x + * @return {Number | Array | Matrix} re + */ + math.re = function re(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('re', arguments.length, 1); + } + + if (isNumber(x)) { + return x; + } + + if (isComplex(x)) { + return x.re; + } + + if (isCollection(x)) { + return collection.map(x, re); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return re(x.valueOf()); + } + + // return a clone of the value itself for all non-complex values + return object.clone(x); + }; +}; diff --git a/lib/function/construction/boolean.js b/lib/function/construction/boolean.js new file mode 100644 index 000000000..0493cb55f --- /dev/null +++ b/lib/function/construction/boolean.js @@ -0,0 +1,48 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + isNumber = util.number.isNumber, + isString = util.string.isString; + + /** + * Create a boolean or convert a string or number to a boolean. + * In case of a number, true is returned for non-zero numbers, and false in + * case of zero. + * Strings can be 'true' or 'false', or can contain a number. + * @param {String | Number | Boolean} value + * @return {Boolean} bool + */ + math['boolean'] = function bool (value) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('boolean', arguments.length, 0, 1); + } + + if (value === 'true' || value === true) { + return true; + } + else if (value === 'false' || value === false) { + return false; + } + else if (isNumber(value)) { + return (value !== 0); + } + else if (isString(value)) { + // try case insensitive + var lcase = value.toLowerCase(); + if (lcase === 'true') { + return true; + } + else if (lcase === 'false') { + return false; + } + + // try whether a number + var num = Number(value); + if (value != '' && !isNaN(num)) { + return (num !== 0); + } + } + + throw new SyntaxError(value.toString() + ' is no valid boolean'); + }; +}; diff --git a/lib/function/construction/complex.js b/lib/function/construction/complex.js new file mode 100644 index 000000000..fa8384411 --- /dev/null +++ b/lib/function/construction/complex.js @@ -0,0 +1,69 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Complex = require('../../type/Complex.js'), + + isString = util.string.isString, + isComplex = Complex.isComplex; + + /** + * Create a complex value. Depending on the passed arguments, the function + * will create and return a new math.type.Complex object. + * + * The method accepts the following arguments: + * complex() creates a complex value with zero + * as real and imaginary part. + * complex(re : number, im : string) creates a complex value with provided + * values for real and imaginary part. + * complex(arg : string) parses a string into a complex value. + * + * Example usage: + * var a = math.complex(3, -4); // 3 - 4i + * a.re = 5; // a = 5 - 4i + * var i = a.im; // -4; + * var b = math.complex('2 + 6i'); // 2 + 6i + * var c = math.complex(); // 0 + 0i + * var d = math.add(a, b); // 5 + 2i + * + * @param {*} [args] + * @return {Complex} value + */ + math.complex = function complex(args) { + switch (arguments.length) { + case 0: + // no parameters. Set re and im zero + return new Complex(0, 0); + break; + + case 1: + // parse string into a complex number + var arg = arguments[0]; + if (isComplex(arg)) { + // create a clone + return arg.clone(); + } + else if (isString(arg)) { + var c = Complex.parse(arg); + if (c) { + return c; + } + else { + throw new SyntaxError('String "' + arg + '" is no valid complex number'); + } + } + else { + throw new TypeError( + 'Two numbers or a single string expected in function complex'); + } + break; + + case 2: + // re and im provided + return new Complex(arguments[0], arguments[1]); + break; + + default: + throw new util.error.ArgumentsError('complex', arguments.length, 0, 2); + } + }; +}; diff --git a/lib/function/construction/matrix.js b/lib/function/construction/matrix.js new file mode 100644 index 000000000..5fd34b4ac --- /dev/null +++ b/lib/function/construction/matrix.js @@ -0,0 +1,30 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Matrix = require('../../type/Matrix.js'); + + /** + * Create a matrix. The function creates a new math.type.Matrix object. + * + * The method accepts the following arguments: + * matrix() creates an empty matrix + * matrix(data) creates a matrix with initial data. + * + * Example usage: + * var m = matrix([[1, 2], [3, 4]); + * m.size(); // [2, 2] + * m.resize([3, 2], 5); + * m.valueOf(); // [[1, 2], [3, 4], [5, 5]] + * m.get([1, 0]) // 3 + * + * @param {Array | Matrix} [data] A multi dimensional array + * @return {Matrix} matrix + */ + math.matrix = function matrix(data) { + if (arguments.length > 1) { + throw new util.error.ArgumentsError('matrix', arguments.length, 0, 1); + } + + return new Matrix(data); + }; +}; diff --git a/lib/function/construction/number.js b/lib/function/construction/number.js new file mode 100644 index 000000000..81a6a3d08 --- /dev/null +++ b/lib/function/construction/number.js @@ -0,0 +1,26 @@ +module.exports = function (math) { + var util = require('../../util/index.js'); + + /** + * Create a number or convert a string to a number + * @param {String | Number | Boolean} [value] + * @return {Number} num + */ + math.number = function number (value) { + switch (arguments.length) { + case 0: + return 0; + case 1: + var num = Number(value); + if (isNaN(num)) { + num = Number(value.valueOf()); + } + if (isNaN(num)) { + throw new SyntaxError(value.toString() + ' is no valid number'); + } + return num; + default: + throw new util.error.ArgumentsError('number', arguments.length, 0, 1); + } + }; +}; diff --git a/lib/function/construction/parser.js b/lib/function/construction/parser.js new file mode 100644 index 000000000..3d3e7e56e --- /dev/null +++ b/lib/function/construction/parser.js @@ -0,0 +1,45 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Parser = require('../../expr/Parser.js'); + + /** + * Create a parser. The function creates a new math.expr.Parser object. + * + * parser() + * + * Example usage: + * var parser = new math.parser(); + * + * // evaluate expressions + * var a = parser.eval('sqrt(3^2 + 4^2)'); // 5 + * var b = parser.eval('sqrt(-4)'); // 2i + * var c = parser.eval('2 inch in cm'); // 5.08 cm + * var d = parser.eval('cos(45 deg)'); // 0.7071067811865476 + * + * // define variables and functions + * parser.eval('x = 7 / 2'); // 3.5 + * parser.eval('x + 3'); // 6.5 + * parser.eval('function f(x, y) = x^y'); // f(x, y) + * parser.eval('f(2, 3)'); // 8 + * + * // get and set variables and functions + * var x = parser.get('x'); // 7 + * var f = parser.get('f'); // function + * var g = f(3, 2); // 9 + * parser.set('h', 500); + * var i = parser.eval('h / 2'); // 250 + * parser.set('hello', function (name) { + * return 'hello, ' + name + '!'; + * }); + * parser.eval('hello("user")'); // "hello, user!" + * + * // clear defined functions and variables + * parser.clear(); + * + * @return {Parser} Parser + */ + math.parser = function parser() { + return new Parser(math); + }; +}; diff --git a/lib/function/construction/range.js b/lib/function/construction/range.js new file mode 100644 index 000000000..8762d195b --- /dev/null +++ b/lib/function/construction/range.js @@ -0,0 +1,73 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Range = require('../../type/Range.js'), + + isString = util.string.isString; + + /** + * Create a range. The function creates a new math.type.Range object. + * + * A range works similar to an Array, with functions like + * forEach and map. However, a Range object is very cheap to create compared to + * a large Array with indexes, as it stores only a start, step and end value of + * the range. + * + * The method accepts the following arguments + * range(str) Create a range from a string, where the + * string contains the start, optional step, + * and end, separated by a colon. + * range(start, end) Create a range with start and end and a + * default step size of 1 + * range(start, end, step) Create a range with start, step, and end. + * + * Example usage: + * var c = math.range(2, 6); // 2:1:5 + * c.toArray(); // [2, 3, 4, 5] + * var d = math.range(2, -3, -1); // 2:-1:-2 + * d.forEach(function (value, index) { + * console.log(index, value); + * }); + * var e = math.range('2:1:6'); // 2:1:6 + * + * @param {...*} args + * @return {Range} range + */ + math.range = function range(args) { + switch (arguments.length) { + case 1: + // parse string into a range + if (args instanceof Range) { + // create a clone + return args.clone(); + } + else if (isString(args)) { + var r = Range.parse(args); + if (r) { + return r; + } + else { + throw new SyntaxError('String "' + r + '" is no valid range'); + } + } + else { + throw new TypeError( + 'Two or three numbers or a single string expected in function range'); + } + break; + + case 2: + // range(start, end) + return new Range(arguments[0], arguments[1]); + break; + + case 3: + // range(start, end, step) + return new Range(arguments[0], arguments[1], arguments[2]); + break; + + default: + throw new util.error.ArgumentsError('range', arguments.length, 2, 3); + } + }; +}; diff --git a/lib/function/construction/string.js b/lib/function/construction/string.js new file mode 100644 index 000000000..f27d37065 --- /dev/null +++ b/lib/function/construction/string.js @@ -0,0 +1,56 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + collection = require('../../type/collection.js'), + + number = util.number, + isNumber = util.number.isNumber, + isCollection = collection.isCollection; + + /** + * Create a string or convert any object into a string + * @param {*} [value] + * @return {String} str + */ + math.string = function string (value) { + switch (arguments.length) { + case 0: + return ''; + + case 1: + return _toString(value); + + default: + throw new util.error.ArgumentsError('string', arguments.length, 0, 1); + } + }; + + /** + * Recursive toString function + * @param {*} value Value can be anything: number, string, array, Matrix, ... + * @returns {String} str + * @private + */ + function _toString(value) { + if (isCollection(value)) { + var array = value.valueOf(); + + var str = '['; + var len = array.length; + for (var i = 0; i < len; i++) { + if (i != 0) { + str += ', '; + } + str += _toString(array[i]); + } + str += ']'; + return str; + } + else if (isNumber(value)) { + return number.format(value); + } + else { + return value.toString(); + } + } +}; diff --git a/lib/function/construction/unit.js b/lib/function/construction/unit.js new file mode 100644 index 000000000..e5a311ba1 --- /dev/null +++ b/lib/function/construction/unit.js @@ -0,0 +1,59 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Unit = require('../../type/Unit.js'), + + isString = util.string.isString; + + /** + * Create a unit. Depending on the passed arguments, the function + * will create and return a new math.type.Unit object. + * + * The method accepts the following arguments: + * unit(unit : string) + * unit(value : number, unit : string + * + * Example usage: + * var a = math.unit(5, 'cm'); // 50 mm + * var b = math.unit('23 kg'); // 23 kg + * var c = math.in(a, math.unit('m'); // 0.05 m + * + * @param {*} args + * @return {Unit} value + */ + math.unit = function unit(args) { + switch(arguments.length) { + case 1: + // parse a string + var arg = arguments[0]; + if (arg instanceof Unit) { + // create a clone of the unit + return arg.clone(); + } + else if (isString(arg)) { + if (Unit.isPlainUnit(arg)) { + return new Unit(null, arg); // a pure unit + } + + var u = Unit.parse(arg); // a unit with value, like '5cm' + if (u) { + return u; + } + + throw new SyntaxError('String "' + arg + '" is no valid unit'); + } + else { + throw new TypeError('A string or a number and string expected in function unit'); + } + break; + + case 2: + // a number and a unit + return new Unit(arguments[0], arguments[1]); + break; + + default: + throw new util.error.ArgumentsError('unit', arguments.length, 1, 2); + } + }; +}; diff --git a/lib/function/matrix/concat.js b/lib/function/matrix/concat.js new file mode 100644 index 000000000..69a7340b6 --- /dev/null +++ b/lib/function/matrix/concat.js @@ -0,0 +1,115 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Matrix = require('../../type/Matrix.js'), + collection = require('../../type/collection.js'), + + object = util.object, + array = util.array, + isNumber = util.number.isNumber, + isInteger = util.number.isInteger, + isCollection = collection.isCollection; + + /** + * Concatenate two or more matrices + * Usage: + * math.concat(A, B, C, ...) + * math.concat(A, B, C, ..., dim) + * + * Where the optional dim is the zero-based number of the dimension to be + * concatenated. + * + * @param {... Array | Matrix} args + * @return {Array | Matrix} res + */ + math.concat = function concat (args) { + var i, + len = arguments.length, + dim = -1, // zero-based dimension + prevDim, + asMatrix = false, + matrices = []; // contains multi dimensional arrays + + for (i = 0; i < len; i++) { + var arg = arguments[i]; + + // test whether we need to return a Matrix (if not we return an Array) + if (arg instanceof Matrix) { + asMatrix = true; + } + + if ((i == len - 1) && isNumber(arg)) { + // last argument contains the dimension on which to concatenate + prevDim = dim; + dim = arg; + + if (!isInteger(dim) || dim < 0) { + throw new TypeError('Dimension number must be a positive integer ' + + '(dim = ' + dim + ')'); + } + + if (i > 0 && dim > prevDim) { + throw new RangeError('Dimension out of range ' + + '(' + dim + ' > ' + prevDim + ')'); + } + } + else if (isCollection(arg)) { + // this is a matrix or array + var matrix = object.clone(arg).valueOf(); + var size = array.size(arg.valueOf()); + matrices[i] = matrix; + prevDim = dim; + dim = size.length - 1; + + // verify whether each of the matrices has the same number of dimensions + if (i > 0 && dim != prevDim) { + throw new RangeError('Dimension mismatch ' + + '(' + prevDim + ' != ' + dim + ')'); + } + } + else { + throw new util.error.UnsupportedTypeError('concat', arg); + } + } + + if (matrices.length == 0) { + throw new SyntaxError('At least one matrix expected'); + } + + var res = matrices.shift(); + while (matrices.length) { + res = _concat(res, matrices.shift(), dim, 0); + } + + return asMatrix ? new Matrix(res) : res; + }; + + /** + * Recursively concatenate two matrices. + * The contents of the matrices is not cloned. + * @param {Array} a Multi dimensional array + * @param {Array} b Multi dimensional array + * @param {Number} concatDim The dimension on which to concatenate (zero-based) + * @param {Number} dim The current dim (zero-based) + * @return {Array} c The concatenated matrix + * @private + */ + function _concat(a, b, concatDim, dim) { + if (dim < concatDim) { + // recurse into next dimension + if (a.length != b.length) { + throw new Error('Dimensions mismatch (' + a.length + ' != ' + b.length + ')'); + } + + var c = []; + for (var i = 0; i < a.length; i++) { + c[i] = _concat(a[i], b[i], concatDim, dim + 1); + } + return c; + } + else { + // concatenate this dimension + return a.concat(b); + } + } +}; diff --git a/lib/function/matrix/det.js b/lib/function/matrix/det.js new file mode 100644 index 000000000..32566a4bc --- /dev/null +++ b/lib/function/matrix/det.js @@ -0,0 +1,143 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Matrix = require('../../type/Matrix.js'), + + object = util.object, + array = util.array, + string = util.string; + + /** + * @constructor det + * Calculate the determinant of a matrix + * + * det(x) + * + * @param {Array | Matrix} x + * @return {Number} determinant + */ + math.det = function det (x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('det', arguments.length, 1); + } + + var size = array.size(x.valueOf()); + switch (size.length) { + case 0: + // scalar + return object.clone(x); + break; + + case 1: + // vector + if (size[0] == 1) { + return object.clone(x.valueOf()[0]); + } + else { + throw new RangeError('Matrix must be square ' + + '(size: ' + string.format(size) + ')'); + } + break; + + case 2: + // two dimensional array + var rows = size[0]; + var cols = size[1]; + if (rows == cols) { + return _det(x.valueOf(), rows, cols); + } + else { + throw new RangeError('Matrix must be square ' + + '(size: ' + string.format(size) + ')'); + } + break; + + default: + // multi dimensional array + throw new RangeError('Matrix must be two dimensional ' + + '(size: ' + string.format(size) + ')'); + } + }; + + /** + * Calculate the determinant of a matrix + * @param {Array[]} matrix A square, two dimensional matrix + * @param {Number} rows Number of rows of the matrix (zero-based) + * @param {Number} cols Number of columns of the matrix (zero-based) + * @returns {Number} det + * @private + */ + function _det (matrix, rows, cols) { + if (rows == 1) { + // this is a 1 x 1 matrix + return matrix[0][0]; + } + else if (rows == 2) { + // this is a 2 x 2 matrix + // the determinant of [a11,a12;a21,a22] is det = a11*a22-a21*a12 + return math.subtract( + math.multiply(matrix[0][0], matrix[1][1]), + math.multiply(matrix[1][0], matrix[0][1]) + ); + } + else { + // this is an n x n matrix + var d = 1; + var lead = 0; + for (var r = 0; r < rows; r++) { + if (lead >= cols) { + break; + } + var i = r; + // Find the pivot element. + while (matrix[i][lead] == 0) { + i++; + if (i == rows) { + i = r; + lead++; + if (lead == cols) { + // We found the last pivot. + if (object.deepEqual(matrix, eye(rows).valueOf())) { + return math.round(d, 6); + } else { + return 0; + } + } + } + } + if (i != r) { + // Swap rows i and r, which negates the determinant. + for (var a = 0; a < cols; a++) { + var temp = matrix[i][a]; + matrix[i][a] = matrix[r][a]; + matrix[r][a] = temp; + } + d *= -1; + } + // Scale row r and the determinant simultaneously. + var div = matrix[r][lead]; + for (var a = 0; a < cols; a++) { + matrix[r][a] = matrix[r][a] / div; + } + d *= div; + // Back-substitute upwards. + for (var j = 0; j < rows; j++) { + if (j != r) { + // Taking linear combinations does not change the det. + var c = matrix[j][lead]; + for (var a = 0; a < cols; a++) { + matrix[j][a] = matrix[j][a] - matrix[r][a] * c; + } + } + } + lead++; // Now looking for a pivot further right. + } + // If reduction did not result in the identity, the matrix is singular. + if (object.deepEqual(matrix, math.eye(rows).valueOf())) { + return math.round(d, 6); + } else { + return 0; + } + } + } +}; diff --git a/lib/function/matrix/diag.js b/lib/function/matrix/diag.js new file mode 100644 index 000000000..867dd8104 --- /dev/null +++ b/lib/function/matrix/diag.js @@ -0,0 +1,87 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Range = require('../../type/Range.js'), + Matrix = require('../../type/Matrix.js'), + + object = util.object, + isNumber = util.number.isNumber, + isInteger = util.number.isInteger; + + /** + * Create a diagonal matrix or retrieve the diagonal of a matrix + * + * diag(v) + * diag(v, k) + * diag(X) + * diag(X, k) + * + * TODO: more documentation on diag + * + * @param {Number | Matrix | Array} x + * @param {Number} [k] + * @return {Matrix} matrix + */ + math.diag = function diag (x, k) { + var data, vector, i, iMax; + + if (arguments.length != 1 && arguments.length != 2) { + throw new util.error.ArgumentsError('diag', arguments.length, 1, 2); + } + + if (k) { + if (!isNumber(k) || !isInteger(k)) { + throw new TypeError ('Second parameter in function diag must be an integer'); + } + } + else { + k = 0; + } + var kSuper = k > 0 ? k : 0; + var kSub = k < 0 ? -k : 0; + + // convert to matrix + if (!(x instanceof Matrix) && !(x instanceof Range)) { + x = new Matrix(x); + } + + // get as array when the matrix is a vector + var s; + if (x.isVector()) { + x = x.toVector(); + s = [x.length]; + } + else { + s = x.size(); + } + + switch (s.length) { + case 1: + // x is a vector. create diagonal matrix + vector = x.valueOf(); + var matrix = new Matrix(); + matrix.resize([vector.length + kSub, vector.length + kSuper]); + data = matrix.valueOf(); + iMax = vector.length; + for (i = 0; i < iMax; i++) { + data[i + kSub][i + kSuper] = object.clone(vector[i]); + } + return matrix; + break; + + case 2: + // x is a matrix get diagonal from matrix + vector = []; + data = x.valueOf(); + iMax = Math.min(s[0] - kSub, s[1] - kSuper); + for (i = 0; i < iMax; i++) { + vector[i] = object.clone(data[i + kSub][i + kSuper]); + } + return new Matrix(vector); + break; + + default: + throw new RangeError('Matrix for function diag must be 2 dimensional'); + } + }; +}; diff --git a/lib/function/matrix/eye.js b/lib/function/matrix/eye.js new file mode 100644 index 000000000..d19367165 --- /dev/null +++ b/lib/function/matrix/eye.js @@ -0,0 +1,58 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Matrix = require('../../type/Matrix.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isInteger = util.number.isInteger; + + /** + * Create an identity matrix with size m x n + * + * eye(m) + * eye(m, n) + * + * TODO: more documentation on eye + * + * @param {...Number | Matrix | Array} size + * @return {Matrix} matrix + */ + math.eye = function eye (size) { + var args = collection.argsToArray(arguments); + if (args.length == 0) { + args = [1, 1]; + } + else if (args.length == 1) { + args[1] = args[0]; + } + else if (args.length > 2) { + throw new util.error.ArgumentsError('eye', args.length, 0, 2); + } + + var rows = args[0], + cols = args[1]; + + if (!isNumber(rows) || !isInteger(rows) || rows < 1) { + throw new Error('Parameters in function eye must be positive integers'); + } + if (cols) { + if (!isNumber(cols) || !isInteger(cols) || cols < 1) { + throw new Error('Parameters in function eye must be positive integers'); + } + } + + // create and args the matrix + var matrix = new Matrix(); + matrix.resize(args); + + // fill in ones on the diagonal + var minimum = math.min(args); + var data = matrix.valueOf(); + for (var d = 0; d < minimum; d++) { + data[d][d] = 1; + } + + return matrix; + }; +}; diff --git a/lib/function/matrix/inv.js b/lib/function/matrix/inv.js new file mode 100644 index 000000000..6aa7fd286 --- /dev/null +++ b/lib/function/matrix/inv.js @@ -0,0 +1,185 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Matrix = require('../../type/Matrix.js'), + + string = util.string; + + /** + * Calculate the inverse of a matrix + * + * inv(x) + * + * TODO: more documentation on inv + * + * @param {Number | Complex | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} inv + */ + math.inv = function inv (x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('inv', arguments.length, 1); + } + var size = math.size(x).valueOf(); + switch (size.length) { + case 0: + // scalar + return math.divide(1, x); + break; + + case 1: + // vector + if (size[0] == 1) { + if (x instanceof Matrix) { + return new Matrix([ + math.divide(1, x.valueOf()[0]) + ]); + } + else { + return [ + math.divide(1, x[0]) + ]; + } + } + else { + throw new RangeError('Matrix must be square ' + + '(size: ' + string.format(size) + ')'); + } + break; + + case 2: + // two dimensional array + var rows = size[0]; + var cols = size[1]; + if (rows == cols) { + if (x instanceof Matrix) { + return new Matrix( + _inv(x.valueOf(), rows, cols) + ); + } + else { + // return an Array + return _inv(x, rows, cols); + } + } + else { + throw new RangeError('Matrix must be square ' + + '(size: ' + string.format(size) + ')'); + } + break; + + default: + // multi dimensional array + throw new RangeError('Matrix must be two dimensional ' + + '(size: ' + string.format(size) + ')'); + } + }; + + /** + * Calculate the inverse of a square matrix + * @param {Array[]} matrix A square matrix + * @param {Number} rows Number of rows + * @param {Number} cols Number of columns, must equal rows + * @return {Array[]} inv Inverse matrix + * @private + */ + function _inv (matrix, rows, cols){ + var r, s, f, value, temp; + + if (rows == 1) { + // this is a 1 x 1 matrix + value = matrix[0][0]; + if (value == 0) { + throw Error('Cannot calculate inverse, determinant is zero'); + } + return [[ + math.divide(1, value) + ]]; + } + else if (rows == 2) { + // this is a 2 x 2 matrix + var d = math.det(matrix); + if (d == 0) { + throw Error('Cannot calculate inverse, determinant is zero'); + } + return [ + [ + math.divide(matrix[1][1], d), + math.divide(math.unary(matrix[0][1]), d) + ], + [ + math.divide(math.unary(matrix[1][0]), d), + math.divide(matrix[0][0], d) + ] + ]; + } + else { + // this is a matrix of 3 x 3 or larger + // calculate inverse using gauss-jordan elimination + // http://en.wikipedia.org/wiki/Gaussian_elimination + // http://mathworld.wolfram.com/MatrixInverse.html + // http://math.uww.edu/~mcfarlat/inverse.htm + + // make a copy of the matrix (only the arrays, not of the elements) + var A = matrix.concat(); + for (r = 0; r < rows; r++) { + A[r] = A[r].concat(); + } + + // create an identity matrix which in the end will contain the + // matrix inverse + var B = math.eye(rows).valueOf(); + + // loop over all columns, and perform row reductions + for (var c = 0; c < cols; c++) { + // element Acc should be non zero. if not, swap content + // with one of the lower rows + r = c; + while (r < rows && A[r][c] == 0) { + r++; + } + if (r == rows || A[r][c] == 0) { + throw Error('Cannot calculate inverse, determinant is zero'); + } + if (r != c) { + temp = A[c]; A[c] = A[r]; A[r] = temp; + temp = B[c]; B[c] = B[r]; B[r] = temp; + } + + // eliminate non-zero values on the other rows at column c + var Ac = A[c], + Bc = B[c]; + for (r = 0; r < rows; r++) { + var Ar = A[r], + Br = B[r]; + if(r != c) { + // eliminate value at column c and row r + if (Ar[c] != 0) { + f = math.divide(math.unary(Ar[c]), Ac[c]); + + // add (f * row c) to row r to eliminate the value + // at column c + for (s = c; s < cols; s++) { + Ar[s] = math.add(Ar[s], math.multiply(f, Ac[s])); + } + for (s = 0; s < cols; s++) { + Br[s] = math.add(Br[s], math.multiply(f, Bc[s])); + } + } + } + else { + // normalize value at Acc to 1, + // divide each value on row r with the value at Acc + f = Ac[c]; + for (s = c; s < cols; s++) { + Ar[s] = math.divide(Ar[s], f); + } + for (s = 0; s < cols; s++) { + Br[s] = math.divide(Br[s], f); + } + } + } + } + return B; + } + } +}; diff --git a/lib/function/matrix/ones.js b/lib/function/matrix/ones.js new file mode 100644 index 000000000..5161f2660 --- /dev/null +++ b/lib/function/matrix/ones.js @@ -0,0 +1,36 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Matrix = require('../../type/Matrix.js'), + collection = require('../../type/collection.js'), + + array = util.array; + + /** + * Create a matrix filled with ones + * + * ones(n) + * ones(m, n) + * ones([m, n]) + * ones([m, n, p, ...]) + * + * @param {...Number | Array} size + * @return {Array | Matrix | Number} matrix + */ + math.ones = function ones (size) { + var args = collection.argsToArray(arguments); + var asMatrix = (size instanceof Matrix); + + if (args.length == 0) { + // output a scalar + return 1; + } + else { + // output an array or matrix + var res = []; + var defaultValue = 1; + array.resize(res, args, defaultValue); + return asMatrix ? new Matrix(res) : res; + } + }; +}; diff --git a/lib/function/matrix/size.js b/lib/function/matrix/size.js new file mode 100644 index 000000000..317407f2a --- /dev/null +++ b/lib/function/matrix/size.js @@ -0,0 +1,50 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Complex = require('../../type/Complex.js'), + Unit = require('../../type/Unit.js'), + Matrix = require('../../type/Matrix.js'), + + array = util.array, + isNumber = util.number.isNumber, + isString = util.string.isString, + isComplex = Complex.isComplex, + isUnit = Unit.isUnit; + + /** + * Calculate the size of a matrix or scalar + * + * size(x) + * + * @param {Number | Complex | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + */ + math.size = function size (x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('size', arguments.length, 1); + } + + if (isNumber(x) || isComplex(x) || isUnit(x) || x == null) { + return []; + } + + if (isString(x)) { + return [x.length]; + } + + if (Array.isArray(x)) { + return array.size(x); + } + + if (x instanceof Matrix) { + return new Matrix(x.size()); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return size(x.valueOf()); + } + + throw new util.error.UnsupportedTypeError('size', x); + }; +}; diff --git a/lib/function/matrix/squeeze.js b/lib/function/matrix/squeeze.js new file mode 100644 index 000000000..a42c25cfe --- /dev/null +++ b/lib/function/matrix/squeeze.js @@ -0,0 +1,59 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Matrix = require('../../type/Matrix.js'), + + object = util.object, + isArray = Array.isArray; + + /** + * Remove singleton dimensions from a matrix + * + * squeeze(x) + * + * @param {Matrix | Array} x + * @return {Matrix | Array} res + */ + math.squeeze = function squeeze (x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('squeeze', arguments.length, 1); + } + + if (isArray(x)) { + return _squeezeArray(object.clone(x)); + } + else if (x instanceof Matrix) { + return new Matrix(_squeezeArray(x.toArray())); + } + else if (isArray(x.valueOf())) { + return _squeezeArray(object.clone(x.valueOf())); + } + else { + // scalar + return object.clone(x); + } + }; + + /** + * Recursively squeeze a multi dimensional array + * @param {Array} array + * @return {Array} array + * @private + */ + function _squeezeArray(array) { + if (array.length == 1) { + // squeeze this array + return _squeezeArray(array[0]); + } + else { + // process all childs + for (var i = 0, len = array.length; i < len; i++) { + var child = array[i]; + if (isArray(child)) { + array[i] = _squeezeArray(child); + } + } + return array; + } + } +}; diff --git a/lib/function/matrix/subset.js b/lib/function/matrix/subset.js new file mode 100644 index 000000000..059390570 --- /dev/null +++ b/lib/function/matrix/subset.js @@ -0,0 +1,205 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Matrix = require('../../type/Matrix.js'), + Range = require('../../type/Range.js'), + + array = util.array, + isString = util.string.isString, + isArray = Array.isArray; + + /** + * Get or set a subset of a matrix or string + * + * Usage: + * var subset = math.subset(value, index) // retrieve subset + * var value = math.subset(value, index, replacement) // replace subset + * + * Where: + * {*} value An array, matrix, or scalar value + * {Array} index An array containing index values + * {*} replacement An array, matrix, or scalar + * + * @param args + * @return res + */ + math.subset = function subset (args) { + switch (arguments.length) { + case 2: // get subset + return _getSubset(arguments[0], arguments[1]); + + case 3: // set subset + return _setSubset(arguments[0], arguments[1], arguments[2]); + + default: // wrong number of arguments + throw new util.error.ArgumentsError('subset', arguments.length, 2, 3); + } + }; + + /** + * Retrieve a subset of an value such as an Array, Matrix, or String + * @param {*} value Object from which to get a subset + * @param {Array[] | Range[] | Number[] | Matrix} index + * Two dimensional array (size 1 x n) containing + * the indexes to be retrieved. Can also be a two + * dimensional Matrix (size 1 x n), or an Array + * (size 1) containing a Range or a Number. + * @returns {*} subset + * @private + */ + function _getSubset(value, index) { + var m, subset; + + if (isArray(value) || value instanceof Range) { + m = new Matrix(value); + subset = m.get(index); + return subset.valueOf(); + } + else if (value instanceof Matrix) { + return value.get(index); + } + else if (isString(value)) { + return _getSubstring(value, index); + } + else { + // scalar + m = new Matrix([value]); + subset = m.get(index); + return subset.valueOf(); + } + } + + /** + * Retrieve a subset of a string + * @param {String} str String from which to get a substring + * @param {Array[] | Range[] | Number[] | Matrix} index + * Two dimensional array (size 1 x n) containing + * the indexes to be retrieved. Can also be a two + * dimensional Matrix (size 1 x n), or an Array + * (size 1) containing a Range or a Number. + * @returns {string} substring + * @private + */ + function _getSubstring(str, index) { + var i, len; + index = index.valueOf(); // cast from matrix or range to array + if (index.length != 1) { + throw new RangeError('Dimension mismatch (' + index.length + ' != 1)'); + } + + if (isArray(index)) { + index = index[0]; // read first dimension + } + index = index.valueOf(); // cast from matrix or range to array + if (!isArray(index)) { + index = [index]; + } + + var substr = ''; + var strLen = str.length; + for (i = 0, len = index.length; i < len; i++) { + var index_i = index[i]; + array.validateIndex(index_i, strLen); + substr += str.charAt(index_i); // index_i is zero based + } + + return substr; + } + + /** + * Replace a subset in an value such as an Array, Matrix, or String + * @param {*} value Object to be replaced + * @param {Array[] | Range[] | Number[] | Matrix} index + * Two dimensional array (size 1 x n) containing + * the indexes to be replaced. Can also be a two + * dimensional Matrix (size 1 x n), or an Array + * (size 1) containing a Range. + * @param {String} replacement + * @returns {*} result + * @private + */ + function _setSubset(value, index, replacement) { + if (isArray(value) || value instanceof Range) { + var m = new Matrix(math.clone(value)); + m.set(index, replacement); + return m.valueOf(); + } + else if (value instanceof Matrix) { + return value.clone().set(index, replacement); + } + else if (isString(value)) { + return _setSubstring(value, index, replacement); + } + else { + // scalar + m = new Matrix([value]); + m.set(index, replacement); + + if (m.isScalar()) { + // still a scalar + return m.toScalar(); + } + else { + // changed into a matrix. return array + return m.valueOf(); + } + } + } + + /** + * Replace a substring in a string + * @param {String} str String to be replaced + * @param {Array[] | Range[] | Number[] | Matrix} index + * Two dimensional array (size 1 x n) containing + * the indexes to be replaced. Can also be a two + * dimensional Matrix (size 1 x n), or an Array + * (size 1) containing a Range. + * @param {String} replacement Replacement string + * @returns {string} result + * @private + */ + function _setSubstring(str, index, replacement) { + var i, len; + index = index.valueOf(); // cast from matrix or range to array + + if (index.length != 1) { + throw new RangeError('Dimension mismatch (' + index.length + ' != 1)'); + } + if (isArray(index)) { + index = index[0]; // read first dimension + } + index = index.valueOf(); // cast from matrix or range to array + if (!isArray(index)) { + index = [index]; + } + + if (index.length != replacement.length) { + throw new RangeError('Dimension mismatch ' + + '(' + index.length + ' != ' + replacement.length + ')'); + } + + // copy the string into an array with characters + var strLen = str.length; + var chars = []; + for (i = 0; i < strLen; i++) { + chars[i] = str.charAt(i); + } + + for (i = 0, len = index.length; i < len; i++) { + var index_i = index[i]; + array.validateIndex(index_i); + chars[index_i] = replacement.charAt(i); // index_i is zero based + } + + // initialize undefined characters with a space + if (chars.length > strLen) { + for (i = strLen - 1, len = chars.length; i < len; i++) { + if (!chars[i]) { + chars[i] = ' '; + } + } + } + + return chars.join(''); + } +}; diff --git a/lib/function/matrix/transpose.js b/lib/function/matrix/transpose.js new file mode 100644 index 000000000..acde1a1cf --- /dev/null +++ b/lib/function/matrix/transpose.js @@ -0,0 +1,68 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Matrix = require('../../type/Matrix.js'), + + object = util.object, + string = util.string; + + /** + * Create the transpose of a matrix + * + * transpose(x) + * + * @param {Array | Matrix} x + * @return {Array | Matrix} transpose + */ + math.transpose = function transpose (x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('transpose', arguments.length, 1); + } + + var size = math.size(x).valueOf(); + switch (size.length) { + case 0: + // scalar + return object.clone(x); + break; + + case 1: + // vector + return object.clone(x); + break; + + case 2: + // two dimensional array + var rows = size[1], + cols = size[0], + asMatrix = Matrix.isMatrix(x), + data = x.valueOf(), + transposed = [], + transposedRow, + clone = object.clone; + + if (rows === 0) { + // whoops + throw new RangeError('Cannot transpose a 2D matrix with no rows' + + '(size: ' + string.format(size) + ')'); + } + + for (var r = 0; r < rows; r++) { + transposedRow = transposed[r] = []; + for (var c = 0; c < cols; c++) { + transposedRow[c] = clone(data[c][r]); + } + } + if (cols == 0) { + transposed[0] = []; + } + return asMatrix ? new Matrix(transposed) : transposed; + break; + + default: + // multi dimensional array + throw new RangeError('Matrix must be two dimensional ' + + '(size: ' + string.format(size) + ')'); + } + }; +}; diff --git a/lib/function/matrix/zeros.js b/lib/function/matrix/zeros.js new file mode 100644 index 000000000..522cb4aa9 --- /dev/null +++ b/lib/function/matrix/zeros.js @@ -0,0 +1,36 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Matrix = require('../../type/Matrix.js'), + collection = require('../../type/collection.js'), + + array = util.array; + + /** + * create a matrix filled with zeros + * + * zeros(n) + * zeros(m, n) + * zeros([m, n]) + * zeros([m, n, p, ...]) + * + * @param {...Number | Array} size + * @return {Array | Matrix | Number} matrix + */ + math.zeros = function zeros (size) { + var args = collection.argsToArray(arguments); + var asMatrix = (size instanceof Matrix); + + if (args.length == 0) { + // output a scalar + return 0; + } + else { + // output an array or matrix + var res = []; + var defaultValue = 0; + array.resize(res, args, defaultValue); + return asMatrix ? new Matrix(res) : res; + } + }; +}; diff --git a/lib/function/probability/factorial.js b/lib/function/probability/factorial.js new file mode 100644 index 000000000..a5e26ebb0 --- /dev/null +++ b/lib/function/probability/factorial.js @@ -0,0 +1,58 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isInteger = util.number.isInteger, + isCollection = collection.isCollection; + + /** + * Compute the factorial of a value + * + * x! + * factorial(x) + * + * Factorial only supports an integer value as argument. + * For matrices, the function is evaluated element wise. + * + * @Param {Number | Array | Matrix} x + * @return {Number | Array | Matrix} res + */ + math.factorial = function factorial (x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('factorial', arguments.length, 1); + } + + if (isNumber(x)) { + if (!isInteger(x) || x < 0) { + throw new TypeError('Positive integer value expected in function factorial'); + } + + var value = x, + res = value; + value--; + while (value > 1) { + res *= value; + value--; + } + + if (res == 0) { + res = 1; // 0! is per definition 1 + } + + return res; + } + + if (isCollection(x)) { + return collection.map(x, factorial); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return factorial(x.valueOf()); + } + + throw new util.error.UnsupportedTypeError('factorial', x); + }; +}; diff --git a/lib/function/probability/random.js b/lib/function/probability/random.js new file mode 100644 index 000000000..12b214c22 --- /dev/null +++ b/lib/function/probability/random.js @@ -0,0 +1,166 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Matrix = require('../../type/Matrix.js'); + + /** + * Return a random number between 0 and 1 + * + * random() + * + * @return {Number} res + */ + + // Each distribution is a function that takes no argument and when called returns + // a number between 0 and 1. + var distributions = { + + uniform: function() { + return Math.random; + }, + + // Implementation of normal distribution using Box-Muller transform + // ref : http://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform + // We take : mean = 0.5, standard deviation = 1/6 + // so that 99.7% values are in [0, 1]. + normal: function() { + return function() { + var u1, u2, + picked = -1; + // We reject values outside of the interval [0, 1] + // TODO: check if it is ok to do that? + while (picked < 0 || picked > 1) { + u1 = Math.random(); + u2 = Math.random(); + picked = 1/6 * Math.pow(-2 * Math.log(u1), 0.5) * Math.cos(2 * Math.PI * u2) + 0.5; + } + return picked; + } + } + }; + + /** + * Create a distribution object. + * @param {String} name Name of a distribution. + * Choose from 'uniform', 'normal'. + * @return {Object} distribution A distribution object containing functions: + * random([size, min, max]) + * randomInt([min, max]) + * pickRandom(array) + */ + math.distribution = function(name) { + if (!distributions.hasOwnProperty(name)) + throw new Error('unknown distribution ' + name); + + var args = Array.prototype.slice.call(arguments, 1), + distribution = distributions[name].apply(this, args); + + return (function(distribution) { + + // This is the public API for all distributions + var randFunctions = { + + random: function(arg1, arg2, arg3) { + var size, min, max; + if (arguments.length > 3) { + throw new util.error.ArgumentsError('random', arguments.length, 0, 3); + + // `random(max)` or `random(size)` + } else if (arguments.length === 1) { + if (Object.prototype.toString.call(arg1) === '[object Array]') + size = arg1; + else + max = arg1; + // `random(min, max)` or `random(size, max)` + } else if (arguments.length === 2) { + if (Object.prototype.toString.call(arg1) === '[object Array]') + size = arg1; + else { + min = arg1; + max = arg2; + } + // `random(size, min, max)` + } else { + size = arg1; + min = arg2; + max = arg3; + } + + if (max === undefined) max = 1; + if (min === undefined) min = 0; + if (size !== undefined) return new Matrix(_randomDataForMatrix(size, min, max, _random)); + else return _random(min, max); + }, + + randomInt: function(arg1, arg2, arg3) { + var size, min, max; + if (arguments.length > 3 || arguments.length < 1) + throw new util.error.ArgumentsError('randomInt', arguments.length, 1, 3); + + // `randomInt(max)` + else if (arguments.length === 1) max = arg1; + // `randomInt(min, max)` or `randomInt(size, max)` + else if (arguments.length === 2) { + if (Object.prototype.toString.call(arg1) === '[object Array]') + size = arg1; + else { + min = arg1; + max = arg2; + } + // `randomInt(size, min, max)` + } else { + size = arg1; + min = arg2; + max = arg3; + } + + if (min === undefined) min = 0; + if (size !== undefined) return new Matrix(_randomDataForMatrix(size, min, max, _randomInt)); + else return _randomInt(min, max); + }, + + pickRandom: function(possibles) { + if (arguments.length !== 1) + throw new util.error.ArgumentsError('pickRandom', arguments.length, 1); + return possibles[Math.floor(Math.random() * possibles.length)]; + } + + }; + + var _random = function(min, max) { + return min + distribution() * (max - min); + }; + + var _randomInt = function(min, max) { + return Math.floor(min + distribution() * (max - min)); + }; + + // This is a function for generating a random matrix recursively. + var _randomDataForMatrix = function(size, min, max, randFunc) { + var data = [], length, i; + size = size.slice(0); + + if (size.length > 1) { + for (i = 0, length = size.shift(); i < length; i++) + data.push(_randomDataForMatrix(size, min, max, randFunc)); + } else { + for (i = 0, length = size.shift(); i < length; i++) + data.push(randFunc(min, max)); + } + + return data; + }; + + return randFunctions; + + })(distribution); + + }; + + // Default random functions use uniform distribution + // TODO: put random functions in separate files? + var uniformRandFunctions = math.distribution('uniform'); + math.random = uniformRandFunctions.random; + math.randomInt = uniformRandFunctions.randomInt; + math.pickRandom = uniformRandFunctions.pickRandom; +}; diff --git a/lib/function/statistics/max.js b/lib/function/statistics/max.js new file mode 100644 index 000000000..cd4614aca --- /dev/null +++ b/lib/function/statistics/max.js @@ -0,0 +1,103 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Matrix = require('../../type/Matrix.js'), + collection = require('../../type/collection.js'), + + isCollection = collection.isCollection; + + /** + * Compute the maximum value of a list of values + * + * max(a, b, c, ...) + * max([a, b, c, ...]) + * + * @param {... *} args A single matrix or or multiple scalar values + * @return {*} res + */ + math.max = function max(args) { + if (arguments.length == 0) { + throw new Error('Function max requires one or more parameters (0 provided)'); + } + + if (isCollection(args)) { + // max([a, b, c, d, ...]]) + if (arguments.length > 1) { + throw Error('Wrong number of parameters (1 matrix or multiple scalars expected)'); + } + + var size = math.size(args).valueOf(); + + if (size.length == 1) { + // vector + if (args.length == 0) { + throw new Error('Cannot calculate max of an empty vector'); + } + + return _max(args.valueOf()); + } + else if (size.length == 2) { + // 2 dimensional matrix + if (size[0] == 0 || size[1] == 0) { + throw new Error('Cannot calculate max of an empty matrix'); + } + + // TODO: make a generic collection method for this + if (Matrix.isMatrix(args)) { + return new Matrix(_max2(args.valueOf(), size[0], size[1])); + } + else { + return _max2(args, size[0], size[1]); + } + } + else { + // TODO: implement max for n-dimensional matrices + throw new RangeError('Cannot calculate max for multi dimensional matrix'); + } + } + else { + // max(a, b, c, d, ...) + return _max(arguments); + } + }; + + /** + * Calculate the max of a one dimensional array + * @param {Array} array + * @return {Number} max + * @private + */ + function _max(array) { + var res = array[0]; + for (var i = 1, iMax = array.length; i < iMax; i++) { + var value = array[i]; + if (math.larger(value, res)) { + res = value; + } + } + return res; + } + + /** + * Calculate the max of a two dimensional array + * @param {Array} array + * @param {Number} rows + * @param {Number} cols + * @return {Number[]} max + * @private + */ + function _max2(array, rows, cols) { + var res = []; + for (var c = 0; c < cols; c++) { + var max = array[0][c]; + for (var r = 1; r < rows; r++) { + var value = array[r][c]; + if (math.larger(value, max)) { + max = value; + } + } + res[c] = max; + } + return res; + } +}; diff --git a/lib/function/statistics/min.js b/lib/function/statistics/min.js new file mode 100644 index 000000000..a1260a079 --- /dev/null +++ b/lib/function/statistics/min.js @@ -0,0 +1,103 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Matrix = require('../../type/Matrix.js'), + collection = require('../../type/collection.js'), + + isCollection = collection.isCollection; + + /** + * Compute the minimum value of a list of values + * + * min(a, b, c, ...) + * min([a, b, c, ...]) + * + * @param {... *} args A single matrix or multiple scalars + * @return {*} res + */ + math.min = function min(args) { + if (arguments.length == 0) { + throw new Error('Function min requires one or more parameters (0 provided)'); + } + + if (isCollection(args)) { + // min([a, b, c, d, ...]]) + if (arguments.length > 1) { + throw Error('Wrong number of parameters (1 matrix or multiple scalars expected)'); + } + + var size = math.size(args).valueOf(); + + if (size.length == 1) { + // vector + if (args.length == 0) { + throw new Error('Cannot calculate min of an empty vector'); + } + + return _min(args.valueOf()); + } + else if (size.length == 2) { + // 2 dimensional matrix + if (size[0] == 0 || size[1] == 0) { + throw new Error('Cannot calculate min of an empty matrix'); + } + + // TODO: make a generic collection method for this + if (Matrix.isMatrix(args)) { + return new Matrix(_min2(args.valueOf(), size[0], size[1])); + } + else { + return _min2(args, size[0], size[1]); + } + } + else { + // TODO: implement min for n-dimensional matrices + throw new RangeError('Cannot calculate min for multi dimensional matrix'); + } + } + else { + // min(a, b, c, d, ...) + return _min(arguments); + } + }; + + /** + * Calculate the min of a one dimensional array + * @param {Array} array + * @return {Number} min + * @private + */ + function _min(array) { + var res = array[0]; + for (var i = 1, iMax = array.length; i < iMax; i++) { + var value = array[i]; + if (math.smaller(value, res)) { + res = value; + } + } + return res; + } + + /** + * Calculate the min of a two dimensional array + * @param {Array} array + * @param {Number} rows + * @param {Number} cols + * @return {Number[]} min + * @private + */ + function _min2(array, rows, cols) { + var res = []; + for (var c = 0; c < cols; c++) { + var min = array[0][c]; + for (var r = 1; r < rows; r++) { + var value = array[r][c]; + if (math.smaller(value, min)) { + min = value; + } + } + res[c] = min; + } + return res; + } +}; diff --git a/lib/function/trigonometry/acos.js b/lib/function/trigonometry/acos.js new file mode 100644 index 000000000..04dfc7757 --- /dev/null +++ b/lib/function/trigonometry/acos.js @@ -0,0 +1,85 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Complex = require('../../type/Complex.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isCollection = collection.isCollection; + + /** + * Calculate the inverse cosine of a value + * + * acos(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + * + * @see http://mathworld.wolfram.com/InverseCosine.html + */ + math.acos = function acos(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('acos', arguments.length, 1); + } + + if (isNumber(x)) { + if (x >= -1 && x <= 1) { + return Math.acos(x); + } + else { + return acos(new Complex(x, 0)); + } + } + + if (isComplex(x)) { + // acos(z) = 0.5*pi + i*log(iz + sqrt(1-z^2)) + var temp1 = Complex.create( + x.im * x.im - x.re * x.re + 1.0, + -2.0 * x.re * x.im + ); + var temp2 = math.sqrt(temp1); + var temp3; + if (temp2 instanceof Complex) { + temp3 = Complex.create( + temp2.re - x.im, + temp2.im + x.re + ) + } + else { + temp3 = Complex.create( + temp2 - x.im, + x.re + ) + } + var temp4 = math.log(temp3); + + // 0.5*pi = 1.5707963267948966192313216916398 + if (temp4 instanceof Complex) { + return Complex.create( + 1.57079632679489661923 - temp4.im, + temp4.re + ); + } + else { + return new Complex( + 1.57079632679489661923, + temp4 + ); + } + } + + if (isCollection(x)) { + return collection.map(x, acos); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return acos(x.valueOf()); + } + + throw new util.error.UnsupportedTypeError('acos', x); + }; +}; diff --git a/lib/function/trigonometry/asin.js b/lib/function/trigonometry/asin.js new file mode 100644 index 000000000..97a24ac17 --- /dev/null +++ b/lib/function/trigonometry/asin.js @@ -0,0 +1,82 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Complex = require('../../type/Complex.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isCollection = collection.isCollection; + + /** + * Calculate the inverse sine of a value + * + * asin(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + * + * @see http://mathworld.wolfram.com/InverseSine.html + */ + math.asin = function asin(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('asin', arguments.length, 1); + } + + if (isNumber(x)) { + if (x >= -1 && x <= 1) { + return Math.asin(x); + } + else { + return asin(new Complex(x, 0)); + } + } + + if (isComplex(x)) { + // asin(z) = -i*log(iz + sqrt(1-z^2)) + var re = x.re; + var im = x.im; + var temp1 = Complex.create( + im * im - re * re + 1.0, + -2.0 * re * im + ); + + var temp2 = math.sqrt(temp1); + var temp3; + if (temp2 instanceof Complex) { + temp3 = Complex.create( + temp2.re - im, + temp2.im + re + ); + } + else { + temp3 = Complex.create( + temp2 - im, + re + ); + } + + var temp4 = math.log(temp3); + + if (temp4 instanceof Complex) { + return Complex.create(temp4.im, -temp4.re); + } + else { + return Complex.create(0, -temp4); + } + } + + if (isCollection(x)) { + return collection.map(x, asin); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return asin(x.valueOf()); + } + + throw new util.error.UnsupportedTypeError('asin', x); + }; +}; diff --git a/lib/function/trigonometry/atan.js b/lib/function/trigonometry/atan.js new file mode 100644 index 000000000..98bd03f49 --- /dev/null +++ b/lib/function/trigonometry/atan.js @@ -0,0 +1,69 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Complex = require('../../type/Complex.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isCollection = collection.isCollection; + + /** + * Calculate the inverse tangent of a value + * + * atan(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + * + * @see http://mathworld.wolfram.com/InverseTangent.html + */ + math.atan = function atan(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('atan', arguments.length, 1); + } + + if (isNumber(x)) { + return Math.atan(x); + } + + if (isComplex(x)) { + // atan(z) = 1/2 * i * (ln(1-iz) - ln(1+iz)) + var re = x.re; + var im = x.im; + var den = re * re + (1.0 - im) * (1.0 - im); + + var temp1 = Complex.create( + (1.0 - im * im - re * re) / den, + (-2.0 * re) / den + ); + var temp2 = math.log(temp1); + + if (temp2 instanceof Complex) { + return Complex.create( + -0.5 * temp2.im, + 0.5 * temp2.re + ); + } + else { + return Complex.create( + 0, + 0.5 * temp2 + ); + } + } + + if (isCollection(x)) { + return collection.map(x, atan); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return atan(x.valueOf()); + } + + throw new util.error.UnsupportedTypeError('atan', x); + }; +}; diff --git a/lib/function/trigonometry/atan2.js b/lib/function/trigonometry/atan2.js new file mode 100644 index 000000000..16bbbf4e0 --- /dev/null +++ b/lib/function/trigonometry/atan2.js @@ -0,0 +1,61 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Complex = require('../../type/Complex.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isCollection = collection.isCollection; + + /** + * Computes the principal value of the arc tangent of y/x in radians + * + * atan2(y, x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Array | Matrix} y + * @param {Number | Complex | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + * + * @see http://mathworld.wolfram.com/InverseTangent.html + */ + math.atan2 = function atan2(y, x) { + if (arguments.length != 2) { + throw new util.error.ArgumentsError('atan2', arguments.length, 2); + } + + if (isNumber(y)) { + if (isNumber(x)) { + return Math.atan2(y, x); + } + /* TODO: support for complex computation of atan2 + else if (isComplex(x)) { + return Math.atan2(y.re, x.re); + } + */ + } + else if (isComplex(y)) { + if (isNumber(x)) { + return Math.atan2(y.re, x); + } + /* TODO: support for complex computation of atan2 + else if (isComplex(x)) { + return Math.atan2(y.re, x.re); + } + */ + } + + if (isCollection(y) || isCollection(x)) { + return collection.map2(y, x, atan2); + } + + if (x.valueOf() !== x || y.valueOf() !== y) { + // fallback on the objects primitive values + return atan2(y.valueOf(), x.valueOf()); + } + + throw new util.error.UnsupportedTypeError('atan2', y, x); + }; +}; diff --git a/lib/function/trigonometry/cos.js b/lib/function/trigonometry/cos.js new file mode 100644 index 000000000..52f5b2713 --- /dev/null +++ b/lib/function/trigonometry/cos.js @@ -0,0 +1,60 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Complex = require('../../type/Complex.js'), + Unit = require('../../type/Unit.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isUnit = Unit.isUnit, + isCollection = collection.isCollection; + + /** + * Calculate the cosine of a value + * + * cos(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Unit | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + * + * @see http://mathworld.wolfram.com/Cosine.html + */ + math.cos = function cos(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('cos', arguments.length, 1); + } + + if (isNumber(x)) { + return Math.cos(x); + } + + if (isComplex(x)) { + // cos(z) = (exp(iz) + exp(-iz)) / 2 + return Complex.create( + 0.5 * Math.cos(x.re) * (Math.exp(-x.im) + Math.exp(x.im)), + 0.5 * Math.sin(x.re) * (Math.exp(-x.im) - Math.exp(x.im)) + ); + } + + if (isUnit(x)) { + if (!x.hasBase(Unit.BASE_UNITS.ANGLE)) { + throw new TypeError ('Unit in function cos is no angle'); + } + return Math.cos(x.value); + } + + if (isCollection(x)) { + return collection.map(x, cos); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return cos(x.valueOf()); + } + + throw new util.error.UnsupportedTypeError('cos', x); + }; +}; diff --git a/lib/function/trigonometry/cot.js b/lib/function/trigonometry/cot.js new file mode 100644 index 000000000..b111218aa --- /dev/null +++ b/lib/function/trigonometry/cot.js @@ -0,0 +1,60 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Complex = require('../../type/Complex.js'), + Unit = require('../../type/Unit.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isUnit = Unit.isUnit, + isCollection = collection.isCollection; + + /** + * Calculate the cotangent of a value. cot(x) is defined as 1 / tan(x) + * + * cot(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Unit | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + */ + math.cot = function cot(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('cot', arguments.length, 1); + } + + if (isNumber(x)) { + return 1 / Math.tan(x); + } + + if (isComplex(x)) { + var den = Math.exp(-4.0 * x.im) - + 2.0 * Math.exp(-2.0 * x.im) * Math.cos(2.0 * x.re) + 1.0; + + return Complex.create( + 2.0 * Math.exp(-2.0 * x.im) * Math.sin(2.0 * x.re) / den, + (Math.exp(-4.0 * x.im) - 1.0) / den + ); + } + + if (isUnit(x)) { + if (!x.hasBase(Unit.BASE_UNITS.ANGLE)) { + throw new TypeError ('Unit in function cot is no angle'); + } + return 1 / Math.tan(x.value); + } + + if (isCollection(x)) { + return collection.map(x, cot); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return cot(x.valueOf()); + } + + throw new util.error.UnsupportedTypeError('cot', x); + }; +}; diff --git a/lib/function/trigonometry/csc.js b/lib/function/trigonometry/csc.js new file mode 100644 index 000000000..46071407c --- /dev/null +++ b/lib/function/trigonometry/csc.js @@ -0,0 +1,61 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Complex = require('../../type/Complex.js'), + Unit = require('../../type/Unit.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isUnit = Unit.isUnit, + isCollection = collection.isCollection; + + /** + * Calculate the cosecant of a value, csc(x) = 1/sin(x) + * + * csc(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Unit | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + */ + math.csc = function csc(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('csc', arguments.length, 1); + } + + if (isNumber(x)) { + return 1 / Math.sin(x); + } + + if (isComplex(x)) { + // csc(z) = 1/sin(z) = (2i) / (exp(iz) - exp(-iz)) + var den = 0.25 * (Math.exp(-2.0 * x.im) + Math.exp(2.0 * x.im)) - + 0.5 * Math.cos(2.0 * x.re); + + return Complex.create ( + 0.5 * Math.sin(x.re) * (Math.exp(-x.im) + Math.exp(x.im)) / den, + 0.5 * Math.cos(x.re) * (Math.exp(-x.im) - Math.exp(x.im)) / den + ); + } + + if (isUnit(x)) { + if (!x.hasBase(Unit.BASE_UNITS.ANGLE)) { + throw new TypeError ('Unit in function csc is no angle'); + } + return 1 / Math.sin(x.value); + } + + if (isCollection(x)) { + return collection.map(x, csc); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return csc(x.valueOf()); + } + + throw new util.error.UnsupportedTypeError('csc', x); + }; +}; diff --git a/lib/function/trigonometry/sec.js b/lib/function/trigonometry/sec.js new file mode 100644 index 000000000..257407c97 --- /dev/null +++ b/lib/function/trigonometry/sec.js @@ -0,0 +1,60 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Complex = require('../../type/Complex.js'), + Unit = require('../../type/Unit.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isUnit = Unit.isUnit, + isCollection = collection.isCollection; + + /** + * Calculate the secant of a value, sec(x) = 1/cos(x) + * + * sec(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Unit | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + */ + math.sec = function sec(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('sec', arguments.length, 1); + } + + if (isNumber(x)) { + return 1 / Math.cos(x); + } + + if (isComplex(x)) { + // sec(z) = 1/cos(z) = 2 / (exp(iz) + exp(-iz)) + var den = 0.25 * (Math.exp(-2.0 * x.im) + Math.exp(2.0 * x.im)) + + 0.5 * Math.cos(2.0 * x.re); + return Complex.create( + 0.5 * Math.cos(x.re) * (Math.exp(-x.im) + Math.exp( x.im)) / den, + 0.5 * Math.sin(x.re) * (Math.exp( x.im) - Math.exp(-x.im)) / den + ); + } + + if (isUnit(x)) { + if (!x.hasBase(Unit.BASE_UNITS.ANGLE)) { + throw new TypeError ('Unit in function sec is no angle'); + } + return 1 / Math.cos(x.value); + } + + if (isCollection(x)) { + return collection.map(x, sec); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return sec(x.valueOf()); + } + + throw new util.error.UnsupportedTypeError('sec', x); + }; +}; diff --git a/lib/function/trigonometry/sin.js b/lib/function/trigonometry/sin.js new file mode 100644 index 000000000..09dd5545d --- /dev/null +++ b/lib/function/trigonometry/sin.js @@ -0,0 +1,59 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Complex = require('../../type/Complex.js'), + Unit = require('../../type/Unit.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isUnit = Unit.isUnit, + isCollection = collection.isCollection; + + /** + * Calculate the sine of a value + * + * sin(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Unit | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + * + * @see http://mathworld.wolfram.com/Sine.html + */ + math.sin = function sin(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('sin', arguments.length, 1); + } + + if (isNumber(x)) { + return Math.sin(x); + } + + if (isComplex(x)) { + return Complex.create( + 0.5 * Math.sin(x.re) * (Math.exp(-x.im) + Math.exp( x.im)), + 0.5 * Math.cos(x.re) * (Math.exp( x.im) - Math.exp(-x.im)) + ); + } + + if (isUnit(x)) { + if (!x.hasBase(Unit.BASE_UNITS.ANGLE)) { + throw new TypeError ('Unit in function cos is no angle'); + } + return Math.sin(x.value); + } + + if (isCollection(x)) { + return collection.map(x, sin); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return sin(x.valueOf()); + } + + throw new util.error.UnsupportedTypeError('sin', x); + }; +}; diff --git a/lib/function/trigonometry/tan.js b/lib/function/trigonometry/tan.js new file mode 100644 index 000000000..fb34aae16 --- /dev/null +++ b/lib/function/trigonometry/tan.js @@ -0,0 +1,63 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Complex = require('../../type/Complex.js'), + Unit = require('../../type/Unit.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isUnit = Unit.isUnit, + isCollection = collection.isCollection; + + /** + * Calculate the tangent of a value + * + * tan(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Unit | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + * + * @see http://mathworld.wolfram.com/Tangent.html + */ + math.tan = function tan(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('tan', arguments.length, 1); + } + + if (isNumber(x)) { + return Math.tan(x); + } + + if (isComplex(x)) { + var den = Math.exp(-4.0 * x.im) + + 2.0 * Math.exp(-2.0 * x.im) * Math.cos(2.0 * x.re) + + 1.0; + + return Complex.create( + 2.0 * Math.exp(-2.0 * x.im) * Math.sin(2.0 * x.re) / den, + (1.0 - Math.exp(-4.0 * x.im)) / den + ); + } + + if (isUnit(x)) { + if (!x.hasBase(Unit.BASE_UNITS.ANGLE)) { + throw new TypeError ('Unit in function tan is no angle'); + } + return Math.tan(x.value); + } + + if (isCollection(x)) { + return collection.map(x, tan); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return tan(x.valueOf()); + } + + throw new util.error.UnsupportedTypeError('tan', x); + }; +}; diff --git a/lib/function/units/in.js b/lib/function/units/in.js new file mode 100644 index 000000000..bd4f9c153 --- /dev/null +++ b/lib/function/units/in.js @@ -0,0 +1,47 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Unit = require('../../type/Unit.js'), + collection = require('../../type/collection.js'), + + isString = util.string.isString, + isUnit = Unit.isUnit, + isCollection = collection.isCollection; + + /** + * Change the unit of a value. + * + * x in unit + * in(x, unit) + * + * For matrices, the function is evaluated element wise. + * + * @param {Unit | Array | Matrix} x + * @param {Unit | Array | Matrix} unit + * @return {Unit | Array | Matrix} res + */ + math['in'] = function unit_in(x, unit) { + if (arguments.length != 2) { + throw new util.error.ArgumentsError('in', arguments.length, 2); + } + + if (isUnit(x)) { + if (isUnit(unit) || isString(unit)) { + return x['in'](unit); + } + } + + // TODO: add support for string, in that case, convert to unit + + if (isCollection(x) || isCollection(unit)) { + return collection.map2(x, unit, unit_in); + } + + if (x.valueOf() !== x || unit.valueOf() !== unit) { + // fallback on the objects primitive value + return unit_in(x.valueOf(), unit.valueOf()); + } + + throw new util.error.UnsupportedTypeError('in', x, unit); + }; +}; diff --git a/lib/function/utils/clone.js b/lib/function/utils/clone.js new file mode 100644 index 000000000..45cc62b6c --- /dev/null +++ b/lib/function/utils/clone.js @@ -0,0 +1,20 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + object = util.object; + + /** + * Clone an object + * + * clone(x) + * + * @param {*} x + * @return {*} clone + */ + math.clone = function clone (x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('clone', arguments.length, 1); + } + + return object.clone(x); + }; +}; diff --git a/lib/function/utils/eval.js b/lib/function/utils/eval.js new file mode 100644 index 000000000..600d0cd3e --- /dev/null +++ b/lib/function/utils/eval.js @@ -0,0 +1,72 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Scope = require('../../expr/Scope.js'), + + collection = require('../../type/collection.js'), + + isString = util.string.isString, + isCollection = collection.isCollection; + + /** + * Evaluate an expression. + * + * Syntax: + * + * math.eval(expr) + * math.eval(expr, scope) + * math.eval([expr1, expr2, expr3, ...]) + * math.eval([expr1, expr2, expr3, ...], scope) + * + * Example: + * + * math.eval('(2+3)/4'); // 1.25 + * math.eval('sqrt(3^2 + 4^2)'); // 5 + * math.eval('sqrt(-4)'); // 2i + * math.eval(['a=3', 'b=4', 'a*b']);, // [3, 4, 12] + * + * var scope = {a:3, b:4}; + * math.eval('a * b', scope); // 12 + * + * @param {String | String[] | Matrix} expr + * @param {Scope | Object} [scope] + * @return {*} res + * @throws {Error} + */ + math.eval = function _eval (expr, scope) { + if (arguments.length != 1 && arguments.length != 2) { + throw new util.error.ArgumentsError('eval', arguments.length, 1, 2); + } + + // instantiate a scope + var evalScope; + if (scope) { + if (scope instanceof Scope) { + evalScope = scope; + } + else { + evalScope = new Scope(math, scope); + } + } + else { + evalScope = new Scope(math); + } + + if (isString(expr)) { + // evaluate a single expression + var node = math.parse(expr, evalScope); + return node.eval(); + } + else if (isCollection(expr)) { + // evaluate an array or matrix with expressions + return collection.map(expr, function (elem) { + var node = math.parse(elem, evalScope); + return node.eval(); + }); + } + else { + // oops + throw new TypeError('String or matrix expected'); + } + }; +}; diff --git a/lib/function/utils/format.js b/lib/function/utils/format.js new file mode 100644 index 000000000..f6c5263c6 --- /dev/null +++ b/lib/function/utils/format.js @@ -0,0 +1,32 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + string = util.string; + + /** + * Format a value of any type into a string. Interpolate values into the string. + * Numbers are rounded off to a maximum number of 5 digits by default. + * Usage: + * math.format(value) + * math.format(template, object) + * + * Example usage: + * math.format(2/7); // '0.28571' + * math.format(new Complex(2, 3)); // '2 + 3i' + * math.format('Hello $name! The date is $date', { + * name: 'user', + * date: new Date().toISOString().substring(0, 10) + * }); // 'hello user! The date is 2013-03-23' + * + * @param {String} template + * @param {Object} values + * @return {String} str + */ + math.format = function format (template, values) { + var num = arguments.length; + if (num != 1 && num != 2) { + throw new util.error.ArgumentsError('format', num, 1, 2); + } + + return string.format.apply(string.format, arguments); + }; +}; diff --git a/lib/function/utils/help.js b/lib/function/utils/help.js new file mode 100644 index 000000000..f1d8642ab --- /dev/null +++ b/lib/function/utils/help.js @@ -0,0 +1,58 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Help = require('../../type/Help.js'); + + /** + * Retrieve help on a function or data type. + * Help files are retrieved from the documentation in math.docs. + * @param {function | string | Object} search + * @return {Help} help + */ + math.help = function help(search) { + if (arguments.length != 1) { + throw new SyntaxError('Wrong number of arguments in function help ' + + '(' + arguments.length + ' provided, 1 expected)'); + } + + var text = null; + if ((search instanceof String) || (typeof(search) === 'string')) { + text = search; + } + else { + var prop; + for (prop in math) { + // search in functions and constants + if (math.hasOwnProperty(prop)) { + if (search === math[prop]) { + text = prop; + break; + } + } + } + + if (!text) { + // search data type + for (prop in math.type) { + if (math.type.hasOwnProperty(prop)) { + if (search === math.type[prop]) { + text = prop; + break; + } + } + } + } + } + + if (!text) { + throw new Error('Could not find search term "' + search + '"'); + } + else { + var doc = math.docs[text]; + if (!doc) { + throw new Error('No documentation found on "' + text + '"'); + } + return new Help(math, doc); + } + }; +}; diff --git a/lib/function/utils/import.js b/lib/function/utils/import.js new file mode 100644 index 000000000..45c03860f --- /dev/null +++ b/lib/function/utils/import.js @@ -0,0 +1,120 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Complex = require('../../type/Complex.js'), + Unit = require('../../type/Unit.js'), + + isNumber = util.number.isNumber, + isString = util.string.isString, + isComplex = Complex.isComplex, + isUnit = Unit.isUnit; + + /** + * Import functions from an object or a file + * @param {function | String | Object} object + * @param {Object} [options] Available options: + * {Boolean} override + * If true, existing functions will be + * overwritten. False by default. + * {Boolean} wrap + * If true (default), the functions will + * be wrapped in a wrapper function which + * converts data types like Matrix to + * primitive data types like Array. + * The wrapper is needed when extending + * math.js with libraries which do not + * support the math.js data types. + */ +// TODO: return status information + math['import'] = function math_import(object, options) { + var name; + var opts = { + override: false, + wrap: true + }; + if (options && options instanceof Object) { + util.object.extend(opts, options); + } + + if (isString(object)) { + // a string with a filename + if (typeof (require) !== 'undefined') { + // load the file using require + var _module = require(object); + math_import(_module); + } + else { + throw new Error('Cannot load file: require not available.'); + } + } + else if (isSupportedType(object)) { + // a single function + name = object.name; + if (name) { + if (opts.override || math[name] === undefined) { + _import(name, object, opts); + } + } + else { + throw new Error('Cannot import an unnamed function or object'); + } + } + else if (object instanceof Object) { + // a map with functions + for (name in object) { + if (object.hasOwnProperty(name)) { + var value = object[name]; + if (isSupportedType(value)) { + _import(name, value, opts); + } + else { + math_import(value); + } + } + } + } + }; + + /** + * Add a property to the math namespace and create a chain proxy for it. + * @param {String} name + * @param {*} value + * @param {Object} options See import for a description of the options + * @private + */ + function _import(name, value, options) { + if (options.override || math[name] === undefined) { + // add to math namespace + if (options.wrap && typeof value === 'function') { + // create a wrapper around the function + math[name] = function () { + var args = []; + for (var i = 0, len = arguments.length; i < len; i++) { + args[i] = arguments[i].valueOf(); + } + return value.apply(math, args); + }; + } + else { + // just create a link to the function or value + math[name] = value; + } + + // create a proxy for the Selector + math.expr.Selector.createProxy(name, value); + } + } + + /** + * Check whether given object is a supported type + * @param object + * @return {Boolean} + * @private + */ + function isSupportedType(object) { + return (typeof object == 'function') || + isNumber(object) || isString(object) || + isComplex(object) || isUnit(object); + // TODO: add boolean? + } +}; diff --git a/lib/function/utils/parse.js b/lib/function/utils/parse.js new file mode 100644 index 000000000..f1ea89037 --- /dev/null +++ b/lib/function/utils/parse.js @@ -0,0 +1,1334 @@ +module.exports = function (math) { + var util = require('../../util/index.js'), + + isString = util.string.isString, + isArray = Array.isArray, + + // types + Complex = require('./../../type/Complex.js'), + Matrix = require('./../../type/Matrix.js'), + Unit = require('./../../type/Unit.js'), + Range = require('./../../type/Range.js'), + collection = require('../../type/collection.js'), + + // scope and nodes + Scope = require('./../../expr/Scope.js'), + AssignmentNode = require('../../expr/node/AssignmentNode.js'), + BlockNode = require('../../expr/node/BlockNode.js'), + ConstantNode = require('../../expr/node/ConstantNode.js'), + FunctionNode = require('../../expr/node/FunctionNode.js'), + MatrixNode = require('../../expr/node/MatrixNode.js'), + OperatorNode = require('../../expr/node/OperatorNode.js'), + ParamsNode = require('../../expr/node/ParamsNode.js'), + SymbolNode = require('../../expr/node/SymbolNode.js'), + UpdateNode = require('../../expr/node/UpdateNode.js'), + handlers = require('../../expr/node/handlers.js'); + + /** + * Parse an expression. Returns a node tree, which can be evaluated by + * invoking node.eval(); + * + * Syntax: + * + * math.parse(expr) + * math.parse(expr, scope) + * math.parse([expr1, expr2, expr3, ...]) + * math.parse([expr1, expr2, expr3, ...], scope) + * + * Example: + * + * var node = math.parse('sqrt(3^2 + 4^2)'); + * node.eval(); // 5 + * + * var scope = {a:3, b:4} + * var node = math.parse('a * b', scope); // 12 + * node.eval(); // 12 + * scope.a = 5; + * node.eval(); // 20 + * + * var nodes = math.parse(['a = 3', 'b = 4', 'a * b']); + * nodes[2].eval(); // 12 + * + * @param {String | String[] | Matrix} expr + * @param {Scope | Object} [scope] + * @return {Node | Node[]} node + * @throws {Error} + */ + math.parse = function parse (expr, scope) { + if (arguments.length != 1 && arguments.length != 2) { + throw new util.error.ArgumentsError('parse', arguments.length, 1, 2); + } + + // instantiate a scope + var parseScope; + if (scope) { + if (scope instanceof Scope) { + parseScope = scope; + } + else { + parseScope = new Scope(math, scope); + } + } + else { + parseScope = new Scope(math); + } + + if (isString(expr)) { + // parse a single expression + expression = expr || ''; + return parseStart(parseScope); + } + else if (isArray(expr) || expr instanceof Matrix) { + // parse an array or matrix with expressions + return collection.map(expr, function (elem) { + expression = elem || ''; + return parseStart(parseScope); + }); + } + else { + // oops + throw new TypeError('String or matrix expected'); + } + }; + +// token types enumeration + var TOKENTYPE = { + NULL : 0, + DELIMITER : 1, + NUMBER : 2, + SYMBOL : 3, + UNKNOWN : 4 + }; + +// map with all delimiters + var DELIMITERS = { + ',': true, + '(': true, + ')': true, + '[': true, + ']': true, + '\"': true, + '\n': true, + ';': true, + + '+': true, + '-': true, + '*': true, + '.*': true, + '/': true, + './': true, + '%': true, + '^': true, + '.^': true, + '!': true, + '\'': true, + '=': true, + ':': true, + + '==': true, + '!=': true, + '<': true, + '>': true, + '<=': true, + '>=': true + }; + + var expression = ''; // current expression + var index = 0; // current index in expr + var c = ''; // current token character in expr + var token = ''; // current token + var token_type = TOKENTYPE.NULL; // type of the token + + /** + * Get the first character from the expression. + * The character is stored into the char c. If the end of the expression is + * reached, the function puts an empty string in c. + * @private + */ + function first() { + index = 0; + c = expression.charAt(0); + } + + /** + * Get the next character from the expression. + * The character is stored into the char c. If the end of the expression is + * reached, the function puts an empty string in c. + * @private + */ + function next() { + index++; + c = expression.charAt(index); + } + + /** + * Preview the next character from the expression. + * @return {String} cNext + * @private + */ + function nextPreview() { + return expression.charAt(index + 1); + } + + /** + * Get next token in the current string expr. + * The token and token type are available as token and token_type + * @private + */ + function getToken() { + token_type = TOKENTYPE.NULL; + token = ''; + + // skip over whitespaces + while (c == ' ' || c == '\t') { // space or tab + next(); + } + + // skip comment + if (c == '#') { + while (c != '\n' && c != '') { + next(); + } + } + + // check for end of expression + if (c == '') { + // token is still empty + token_type = TOKENTYPE.DELIMITER; + return; + } + + // check for delimiters consisting of 2 characters + var c2 = c + nextPreview(); + if (DELIMITERS[c2]) { + token_type = TOKENTYPE.DELIMITER; + token = c2; + next(); + next(); + return; + } + + // check for delimiters consisting of 1 character + if (DELIMITERS[c]) { + token_type = TOKENTYPE.DELIMITER; + token = c; + next(); + return; + } + + // check for a number + if (isDigitDot(c)) { + token_type = TOKENTYPE.NUMBER; + + // get number, can have a single dot + if (c == '.') { + token += c; + next(); + + if (!isDigit(c)) { + // this is no legal number, it is just a dot + token_type = TOKENTYPE.UNKNOWN; + } + } + else { + while (isDigit(c)) { + token += c; + next(); + } + if (c == '.') { + token += c; + next(); + } + } + while (isDigit(c)) { + token += c; + next(); + } + + // check for scientific notation like "2.3e-4" or "1.23e50" + if (c == 'E' || c == 'e') { + token += c; + next(); + + if (c == '+' || c == '-') { + token += c; + next(); + } + + // Scientific notation MUST be followed by an exponent + if (!isDigit(c)) { + // this is no legal number, exponent is missing. + token_type = TOKENTYPE.UNKNOWN; + } + + while (isDigit(c)) { + token += c; + next(); + } + } + + return; + } + + // check for variables or functions + if (isAlpha(c)) { + token_type = TOKENTYPE.SYMBOL; + + while (isAlpha(c) || isDigit(c)) { + token += c; + next(); + } + return; + } + + // something unknown is found, wrong characters -> a syntax error + token_type = TOKENTYPE.UNKNOWN; + while (c != '') { + token += c; + next(); + } + throw createSyntaxError('Syntax error in part "' + token + '"'); + } + + /** + * Check if a given name is valid + * if not, an error is thrown + * @param {String} name + * @return {boolean} valid + * @private + */ + // TODO: check for valid symbol name + function isValidSymbolName (name) { + for (var i = 0, iMax = name.length; i < iMax; i++) { + var c = name.charAt(i); + //var valid = (isAlpha(c) || (i > 0 && isDigit(c))); // TODO: allow digits in symbol name + var valid = (isAlpha(c)); + if (!valid) { + return false; + } + } + + return true; + } + + /** + * checks if the given char c is a letter (upper or lower case) + * or underscore + * @param {String} c a string with one character + * @return {Boolean} + * @private + */ + function isAlpha (c) { + return ((c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + c == '_'); + } + + /** + * checks if the given char c is a digit or dot + * @param {String} c a string with one character + * @return {Boolean} + * @private + */ + function isDigitDot (c) { + return ((c >= '0' && c <= '9') || + c == '.'); + } + + /** + * checks if the given char c is a digit + * @param {String} c a string with one character + * @return {Boolean} + * @private + */ + function isDigit (c) { + return ((c >= '0' && c <= '9')); + } + + /** + * Start of the parse levels below, in order of precedence + * @param {Scope} scope + * @return {Node} node + * @private + */ + function parseStart (scope) { + // get the first character in expression + first(); + + getToken(); + + var node; + if (token == '') { + // empty expression + node = new ConstantNode(undefined); + } + else { + node = parseBlock(scope); + } + + // check for garbage at the end of the expression + // an expression ends with a empty character '' and token_type DELIMITER + if (token != '') { + if (token_type == TOKENTYPE.DELIMITER) { + // user entered a not existing operator like "//" + + // TODO: give hints for aliases, for example with "<>" give as hint " did you mean != ?" + throw createError('Unknown operator ' + token); + } + else { + throw createSyntaxError('Unexpected part "' + token + '"'); + } + } + + return node; + } + + /** + * Parse a block with expressions. Expressions can be separated by a newline + * character '\n', or by a semicolon ';'. In case of a semicolon, no output + * of the preceding line is returned. + * @param {Scope} scope + * @return {Node} node + * @private + */ + function parseBlock (scope) { + var node, block, visible; + + if (token != '\n' && token != ';' && token != '') { + node = parseAns(scope); + } + + while (token == '\n' || token == ';') { + if (!block) { + // initialize the block + block = new BlockNode(); + if (node) { + visible = (token != ';'); + block.add(node, visible); + } + } + + getToken(); + if (token != '\n' && token != ';' && token != '') { + node = parseAns(scope); + + visible = (token != ';'); + block.add(node, visible); + } + } + + if (block) { + return block; + } + + if (!node) { + node = parseAns(scope); + } + + return node; + } + + /** + * Parse assignment of ans. + * Ans is assigned when the expression itself is no variable or function + * assignment + * @param {Scope} scope + * @return {Node} node + * @private + */ + function parseAns (scope) { + var expression = parseFunctionAssignment(scope); + + // create a variable definition for ans + var name = 'ans'; + return new AssignmentNode(name, expression, scope); + } + + /** + * Parse a function assignment like "function f(a,b) = a*b" + * @param {Scope} scope + * @return {Node} node + * @private + */ + function parseFunctionAssignment (scope) { + // TODO: keyword 'function' must become a reserved keyword + // TODO: replace the 'function' keyword with an assignment operator '=>' + if (token_type == TOKENTYPE.SYMBOL && token == 'function') { + // get function name + getToken(); + if (token_type != TOKENTYPE.SYMBOL) { + throw createSyntaxError('Function name expected'); + } + var name = token; + + // get parenthesis open + getToken(); + if (token != '(') { + throw createSyntaxError('Opening parenthesis ( expected'); + } + + // get function variables + var functionScope = scope.createSubScope(); + var variables = []; + while (true) { + getToken(); + if (token_type == TOKENTYPE.SYMBOL) { + // store variable name + variables.push(token); + } + else { + throw createSyntaxError('Variable name expected'); + } + + getToken(); + if (token == ',') { + // ok, nothing to do, read next variable + } + else if (token == ')') { + // end of variable list encountered. break loop + break; + } + else { + throw createSyntaxError('Comma , or closing parenthesis ) expected"'); + } + } + + getToken(); + if (token != '=') { + throw createSyntaxError('Equal sign = expected'); + } + + // parse the expression, with the correct function scope + getToken(); + var expression = parseAssignment(functionScope); + + return new FunctionNode(name, variables, expression, functionScope, scope); + } + + return parseAssignment(scope); + } + + /** + * Assignment of a variable, can be a variable like "a=2.3" or a updating an + * existing variable like "matrix(2,3:5)=[6,7,8]" + * @param {Scope} scope + * @return {Node} node + * @private + */ + function parseAssignment (scope) { + var name, params, paramScopes, expr; + + var node = parseRange(scope); + + if (token == '=') { + if (node instanceof SymbolNode) { + // parse the expression, with the correct function scope + getToken(); + name = node.name; + params = null; + expr = parseAssignment(scope); + return new AssignmentNode(name, expr, scope); + } + else if (node instanceof ParamsNode && node.object instanceof SymbolNode) { + // parse the expression, with the correct function scope + getToken(); + name = node.object.name; + params = node.params; + paramScopes = node.paramScopes; + expr = parseAssignment(scope); + return new UpdateNode(math, name, params, paramScopes, expr, scope); + } + else { + throw createSyntaxError('Symbol expected at the left hand side ' + + 'of assignment operator ='); + } + } + + return node; + } + + /** + * parse range, "start:end", "start:step:end", ":", "start:", ":end", etc + * @param {Scope} scope + * @return {Node} node + * @private + */ + function parseRange (scope) { + var node, name, fn, params = []; + + if (token == ':') { + // implicit start=0 + node = new ConstantNode(0); + } + else { + // explicit start + node = parseConditions(scope); + } + + if (token == ':') { + params.push(node); + + // parse step and end + while (token == ':') { + getToken(); + if (token == ')' || token == ',' || token == '') { + // implicit end + params.push(new SymbolNode('end', scope)); + } + else { + // explicit end + params.push(parseConditions(scope)); + } + } + + if (params.length) { + // create a range constructor + name = ':'; + fn = math.range; + + if (params.length >= 3) { + // swap step and end + var step = params[2]; + params[2] = params[1]; // end + params[1] = step; + } + + node = new OperatorNode(name, fn, params); + } + } + + return node; + } + + /** + * conditions like and, or, in + * @param {Scope} scope + * @return {Node} node + * @private + */ + function parseConditions (scope) { + var node, operators, name, fn, params; + + node = parseBitwiseConditions(scope); + + // TODO: precedence of And above Or? + // TODO: implement a method for unit to number conversion + operators = { + 'in' : math['in'] + /* TODO: implement conditions + 'and' : 'and', + '&&' : 'and', + 'or': 'or', + '||': 'or', + 'xor': 'xor' + */ + }; + + while (operators[token] !== undefined) { + name = token; + fn = operators[name]; + + getToken(); + params = [node, parseBitwiseConditions(scope)]; + node = new OperatorNode(name, fn, params); + } + + return node; + } + + /** + * conditional operators and bitshift + * @param {Scope} scope + * @return {Node} node + * @private + */ + function parseBitwiseConditions (scope) { + var node = parseComparison(scope); + + /* TODO: implement bitwise conditions + var operators = { + '&' : bitwiseand, + '|' : bitwiseor, + // todo: bitwise xor? + '<<': bitshiftleft, + '>>': bitshiftright + }; + while (operators[token] !== undefined) { + var name = token; + var fn = operators[name]; + + getToken(); + var params = [node, parseComparison()]; + node = new OperatorNode(name, fn, params); + } + */ + + return node; + } + + /** + * comparison operators + * @param {Scope} scope + * @return {Node} node + * @private + */ + function parseComparison (scope) { + var node, operators, name, fn, params; + + node = parseAddSubtract(scope); + + operators = { + '==': math.equal, + '!=': math.unequal, + '<': math.smaller, + '>': math.larger, + '<=': math.smallereq, + '>=': math.largereq + }; + while (operators[token] !== undefined) { + name = token; + fn = operators[name]; + + getToken(); + params = [node, parseAddSubtract(scope)]; + node = new OperatorNode(name, fn, params); + } + + return node; + } + + /** + * add or subtract + * @param {Scope} scope + * @return {Node} node + * @private + */ + function parseAddSubtract (scope) { + var node, operators, name, fn, params; + + node = parseMultiplyDivide(scope); + + operators = { + '+': math.add, + '-': math.subtract + }; + while (operators[token] !== undefined) { + name = token; + fn = operators[name]; + + getToken(); + params = [node, parseMultiplyDivide(scope)]; + node = new OperatorNode(name, fn, params); + } + + return node; + } + + /** + * multiply, divide, modulus + * @param {Scope} scope + * @return {Node} node + * @private + */ + function parseMultiplyDivide (scope) { + var node, operators, name, fn, params; + + node = parseUnary(scope); + + operators = { + '*': math.multiply, + '.*': math.emultiply, + '/': math.divide, + './': math.edivide, + '%': math.mod, + 'mod': math.mod + }; + + while (operators[token] !== undefined) { + name = token; + fn = operators[name]; + + getToken(); + params = [node, parseUnary(scope)]; + node = new OperatorNode(name, fn, params); + } + + return node; + } + + /** + * Unary minus + * @param {Scope} scope + * @return {Node} node + * @private + */ + function parseUnary (scope) { + var name, fn, params; + + if (token == '-') { + name = token; + fn = math.unary; + getToken(); + params = [parseUnary(scope)]; + + return new OperatorNode(name, fn, params); + } + + return parsePow(scope); + } + + /** + * power + * Node: power operator is right associative + * @param {Scope} scope + * @return {Node} node + * @private + */ + function parsePow (scope) { + var node, leftNode, nodes, ops, name, fn, params; + + nodes = [ + parseFactorial(scope) + ]; + ops = []; + + // stack all operands of a chained power operator (like '2^3^3') + while (token == '^' || token == '.^') { + ops.push(token); + getToken(); + nodes.push(parseFactorial(scope)); + } + + // evaluate the operands from right to left (right associative) + node = nodes.pop(); + while (nodes.length) { + leftNode = nodes.pop(); + name = ops.pop(); + fn = (name == '^') ? math.pow : math.epow; + params = [leftNode, node]; + node = new OperatorNode(name, fn, params); + } + + return node; + } + + /** + * Factorial + * @param {Scope} scope + * @return {Node} node + * @private + */ + function parseFactorial (scope) { + var node, name, fn, params; + + node = parseTranspose(scope); + + while (token == '!') { + name = token; + fn = math.factorial; + getToken(); + params = [node]; + + node = new OperatorNode(name, fn, params); + } + + return node; + } + + /** + * Transpose + * @param {Scope} scope + * @return {Node} node + * @private + */ + function parseTranspose (scope) { + var node, name, fn, params; + + node = parseNodeHandler(scope); + + while (token == '\'') { + name = token; + fn = math.transpose; + getToken(); + params = [node]; + + node = new OperatorNode(name, fn, params); + } + + return node; + } + + /** + * Parse a custom node handler. A node handler can be used to process + * nodes in a custom way, for example for handling a plot. + * + * A handler must be defined in the namespace math.expr.node.handlers, + * and must extend math.expr.node.Node, and the handler must contain + * functions eval(), find(filter), and toString(). + * + * For example: + * + * math.expr.node.handlers['plot'] = PlotHandler; + * + * The constructor of the handler is called as: + * + * node = new PlotHandler(params, paramScopes); + * + * The handler will be invoked when evaluating an expression like: + * + * node = math.parse('plot(sin(x), x)'); + * + * @param {Scope} scope + * @return {Node} node + * @private + */ + function parseNodeHandler (scope) { + var params, + paramScopes, + paramScope, + handler; + + if (token_type == TOKENTYPE.SYMBOL && handlers[token]) { + handler = handlers[token]; + + getToken(); + + // parse parameters + if (token == '(') { + params = []; + paramScopes = []; + + getToken(); + + if (token != ')') { + paramScope = scope.createSubScope(); + paramScopes.push(paramScope); + params.push(parseRange(paramScope)); + + // parse a list with parameters + while (token == ',') { + getToken(); + + paramScope = scope.createSubScope(); + paramScopes.push(paramScope); + params.push(parseRange(paramScope)); + } + } + + if (token != ')') { + throw createSyntaxError('Parenthesis ) expected'); + } + getToken(); + } + + // create a new node handler + //noinspection JSValidateTypes + return new handler(params, paramScopes); + } + + return parseSymbol(scope); + } + + /** + * parse symbols: functions, variables, constants, units + * @param {Scope} scope + * @return {Node} node + * @private + */ + function parseSymbol (scope) { + var node, name; + + if (token_type == TOKENTYPE.SYMBOL) { + name = token; + + getToken(); + + // create a symbol + node = new SymbolNode(name, scope); + + // parse parameters + return parseParams(scope, node); + } + + return parseString(scope); + } + + /** + * parse parameters, enclosed in parenthesis + * @param {Scope} scope + * @param {Node} node Node on which to apply the parameters. If there + * are no parameters in the expression, the node + * itself is returned + * @return {Node} node + * @private + */ + function parseParams (scope, node) { + var params, + paramScopes, + paramScope; + + while (token == '(') { + params = []; + paramScopes = []; + + getToken(); + + if (token != ')') { + paramScope = scope.createSubScope(); + paramScopes.push(paramScope); + params.push(parseRange(paramScope)); + + // parse a list with parameters + while (token == ',') { + getToken(); + + paramScope = scope.createSubScope(); + paramScopes.push(paramScope); + params.push(parseRange(paramScope)); + } + } + + if (token != ')') { + throw createSyntaxError('Parenthesis ) expected'); + } + getToken(); + + node = new ParamsNode(math, node, params, paramScopes); + } + + return node; + } + + /** + * parse a string. + * A string is enclosed by double quotes + * @param {Scope} scope + * @return {Node} node + * @private + */ + function parseString (scope) { + var node, str, tPrev; + + if (token == '"') { + // string "..." + str = ''; + tPrev = ''; + while (c != '' && (c != '\"' || tPrev == '\\')) { // also handle escape character + str += c; + tPrev = c; + next(); + } + + getToken(); + if (token != '"') { + throw createSyntaxError('End of string " expected'); + } + getToken(); + + // create constant + node = new ConstantNode(str); + + // parse parameters + node = parseParams(scope, node); + + return node; + } + + return parseMatrix(scope); + } + + /** + * parse the matrix + * @param {Scope} scope + * @return {Node} A MatrixNode + * @private + */ + function parseMatrix (scope) { + var array, params, r, c, rows, cols; + + if (token == '[') { + // matrix [...] + + // skip newlines + getToken(); + while (token == '\n') { + getToken(); + } + + // check if this is an empty matrix "[ ]" + if (token != ']') { + // this is a non-empty matrix + params = []; + r = 0; + c = 0; + + params[0] = [parseAssignment(scope)]; + + // the columns in the matrix are separated by commas, and the rows by dot-comma's + while (token == ',' || token == ';') { + if (token == ',') { + c++; + } + else { + r++; + c = 0; + params[r] = []; + } + + // skip newlines + getToken(); + while (token == '\n') { + getToken(); + } + + params[r][c] = parseAssignment(scope); + + // skip newlines + while (token == '\n') { + getToken(); + } + } + + // TODO: spaces as separator for matrix columns + /* + // the columns in the matrix are separated by commas or spaces, + // and the rows by dot-comma's + while (token && token != ']') { + if (token == ';') { + r++; + c = 0; + params[r] = []; + getToken(); + } + else if (token == ',') { + c++; + getToken(); + } + else { + c++; + } + + // skip newlines + while (token == '\n') { + getToken(); + } + + //TODO: math.eval('[1 -2 3]') is evaluated as '[(1-2) 3]' instead of '[(1) (-2) (3)]' + //TODO: '[(1) (-2) (3)]' doesn't work + params[r][c] = parseAssignment(scope); + + // skip newlines + while (token == '\n') { + getToken(); + } + } + */ + + rows = params.length; + cols = (params.length > 0) ? params[0].length : 0; + + // check if the number of columns matches in all rows + for (r = 1; r < rows; r++) { + if (params[r].length != cols) { + throw createError('Number of columns must match ' + + '(' + params[r].length + ' != ' + cols + ')'); + } + } + + if (token != ']') { + throw createSyntaxError('End of matrix ] expected'); + } + + getToken(); + array = new MatrixNode(params); + } + else { + // this is an empty matrix "[ ]" + getToken(); + array = new MatrixNode([]); + } + + // parse parameters + array = parseParams(scope, array); + + return array; + } + + return parseNumber(scope); + } + + /** + * parse a number + * @param {Scope} scope + * @return {Node} node + * @private + */ + function parseNumber (scope) { + var node, value, number; + + if (token_type == TOKENTYPE.NUMBER) { + // this is a number + if (token == '.') { + number = 0; + } else { + number = Number(token); + } + getToken(); + + /* TODO: implicit multiplication? + // TODO: how to calculate a=3; 2/2a ? is this (2/2)*a or 2/(2*a) ? + // check for implicit multiplication + if (token_type == TOKENTYPE.VARIABLE) { + node = multiply(node, parsePow()); + } + //*/ + + if (token_type == TOKENTYPE.SYMBOL) { + if (token == 'i' || token == 'I') { + value = new Complex(0, number); + getToken(); + return new ConstantNode(value); + } + + if (Unit.isPlainUnit(token)) { + value = new Unit(number, token); + getToken(); + return new ConstantNode(value); + } + + throw createTypeError('Unknown unit "' + token + '"'); + } + + // just a regular number + node = new ConstantNode(number); + + // parse parameters + node = parseParams(scope, node); + + return node; + } + + return parseParentheses(scope); + } + + /** + * parentheses + * @param {Scope} scope + * @return {Node} node + * @private + */ + function parseParentheses (scope) { + var node; + + // check if it is a parenthesized expression + if (token == '(') { + // parentheses (...) + getToken(); + node = parseAssignment(scope); // start again + + if (token != ')') { + throw createSyntaxError('Parenthesis ) expected'); + } + getToken(); + + /* TODO: implicit multiplication? + // TODO: how to calculate a=3; 2/2a ? is this (2/2)*a or 2/(2*a) ? + // check for implicit multiplication + if (token_type == TOKENTYPE.VARIABLE) { + node = multiply(node, parsePow()); + } + //*/ + + // parse parameters + node = parseParams(scope, node); + + return node; + } + + return parseEnd(scope); + } + + /** + * Evaluated when the expression is not yet ended but expected to end + * @param {Scope} scope + * @return {Node} res + * @private + */ + function parseEnd (scope) { + if (token == '') { + // syntax error or unexpected end of expression + throw createSyntaxError('Unexpected end of expression'); + } else { + throw createSyntaxError('Value expected'); + } + } + + /** + * Shortcut for getting the current row value (one based) + * Returns the line of the currently handled expression + * @private + */ + function row () { + // TODO: also register row number during parsing + return undefined; + } + + /** + * Shortcut for getting the current col value (one based) + * Returns the column (position) where the last token starts + * @private + */ + function col () { + return index - token.length + 1; + } + + /** + * Build up an error message + * @param {String} message + * @return {String} message with row and column information + * @private + */ + function createErrorMessage (message) { + var r = row(); + var c = col(); + if (r === undefined) { + if (c === undefined) { + return message; + } else { + return message + ' (char ' + c + ')'; + } + } else { + return message + ' (line ' + r + ', char ' + c + ')'; + } + } + + /** + * Create an error + * @param {String} message + * @return {SyntaxError} instantiated error + * @private + */ + function createSyntaxError (message) { + return new SyntaxError(createErrorMessage(message)); + } + + /** + * Create an error + * @param {String} message + * @return {TypeError} instantiated error + * @private + */ + function createTypeError(message) { + return new TypeError(createErrorMessage(message)); + } + + /** + * Create an error + * @param {String} message + * @return {Error} instantiated error + * @private + */ + function createError (message) { + return new Error(createErrorMessage(message)); + } +}; diff --git a/lib/function/utils/select.js b/lib/function/utils/select.js new file mode 100644 index 000000000..4ff1b9654 --- /dev/null +++ b/lib/function/utils/select.js @@ -0,0 +1,40 @@ +module.exports = function (math) { + /** + * Wrap any value in a Selector, allowing to perform chained operations on + * the value. + * + * All methods available in the math.js library can be called upon the selector, + * and then will be evaluated with the value itself as first argument. + * The selector can be closed by executing selector.done(), which will return + * the final value. + * + * Example usage: + * math.select(3) + * .add(4) + * .subtract(2) + * .done(); // 5 + * math.select( [[1, 2], [3, 4]] ) + * .set([1, 1], 8) + * .multiply(3) + * .done(); // [[24, 6], [9, 12]] + * + * The Selector has a number of special functions: + * - done() Finalize the chained operation and return the selectors value. + * - valueOf() The same as done() + * - toString() Executes math.format() onto the selectors value, returning + * a string representation of the value. + * - get(...) Get a subselection of the selectors value. Only applicable when + * the value has a method get, for example when value is a Matrix + * or Array. + * - set(...) Replace a subselection of the selectors value. Only applicable + * when the value has a method get, for example when value is a + * Matrix or Array. + * + * @param {*} value + * @return {math.expr.Selector} selector + */ + math.select = function select(value) { + // TODO: check number of arguments + return new math.expr.Selector(value); + }; +}; diff --git a/lib/function/utils/typeof.js b/lib/function/utils/typeof.js new file mode 100644 index 000000000..d9ca56e2e --- /dev/null +++ b/lib/function/utils/typeof.js @@ -0,0 +1,20 @@ +module.exports = function (math) { + var util = require('../../util/index.js'); + + /** + * Determine the type of a variable + * + * typeof(x) + * + * @param {*} x + * @return {String} type Lower case type, for example "number", "string", + * "array". + */ + math['typeof'] = function _typeof (x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('typeof', arguments.length, 1); + } + + return util.types.type(x); + }; +}; diff --git a/lib/header.js b/lib/header.js new file mode 100644 index 000000000..5bfcef3ad --- /dev/null +++ b/lib/header.js @@ -0,0 +1,26 @@ +/** + * math.js + * https://github.com/josdejong/mathjs + * + * Math.js is an extensive math library for JavaScript and Node.js, + * It features real and complex numbers, units, matrices, a large set of + * mathematical functions, and a flexible expression parser. + * + * @version @@version + * @date @@date + * + * @license + * Copyright (C) 2013 Jos de Jong + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ diff --git a/lib/options.js b/lib/options.js new file mode 100644 index 000000000..957acc966 --- /dev/null +++ b/lib/options.js @@ -0,0 +1,2 @@ +// math.js options +exports.precision = 5; // number of digits in formatted output diff --git a/lib/shim.js b/lib/shim.js new file mode 100644 index 000000000..88289382b --- /dev/null +++ b/lib/shim.js @@ -0,0 +1,183 @@ +/** + * Compatibility shims for legacy JavaScript engines + */ + +// http://soledadpenades.com/2007/05/17/arrayindexof-in-internet-explorer/ +if(!Array.prototype.indexOf) { + Array.prototype.indexOf = function(obj){ + for(var i = 0; i < this.length; i++){ + if(this[i] == obj){ + return i; + } + } + return -1; + }; +} + +// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach +if (!Array.prototype.forEach) { + Array.prototype.forEach = function(fn, scope) { + for(var i = 0, len = this.length; i < len; ++i) { + fn.call(scope || this, this[i], i, this); + } + } +} + +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray +if(!Array.isArray) { + Array.isArray = function (vArg) { + return Object.prototype.toString.call(vArg) === "[object Array]"; + }; +} + +// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/map +// Production steps of ECMA-262, Edition 5, 15.4.4.19 +// Reference: http://es5.github.com/#x15.4.4.19 +if (!Array.prototype.map) { + Array.prototype.map = function(callback, thisArg) { + + var T, A, k; + + if (this == null) { + throw new TypeError(" this is null or not defined"); + } + + // 1. Let O be the result of calling ToObject passing the |this| value as the argument. + var O = Object(this); + + // 2. Let lenValue be the result of calling the Get internal method of O with the argument "length". + // 3. Let len be ToUint32(lenValue). + var len = O.length >>> 0; + + // 4. If IsCallable(callback) is false, throw a TypeError exception. + // See: http://es5.github.com/#x9.11 + if (typeof callback !== "function") { + throw new TypeError(callback + " is not a function"); + } + + // 5. If thisArg was supplied, let T be thisArg; else let T be undefined. + if (thisArg) { + T = thisArg; + } + + // 6. Let A be a new array created as if by the expression new Array(len) where Array is + // the standard built-in constructor with that name and len is the value of len. + A = new Array(len); + + // 7. Let k be 0 + k = 0; + + // 8. Repeat, while k < len + while(k < len) { + + var kValue, mappedValue; + + // a. Let Pk be ToString(k). + // This is implicit for LHS operands of the in operator + // b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk. + // This step can be combined with c + // c. If kPresent is true, then + if (k in O) { + + // i. Let kValue be the result of calling the Get internal method of O with argument Pk. + kValue = O[ k ]; + + // ii. Let mappedValue be the result of calling the Call internal method of callback + // with T as the this value and argument list containing kValue, k, and O. + mappedValue = callback.call(T, kValue, k, O); + + // iii. Call the DefineOwnProperty internal method of A with arguments + // Pk, Property Descriptor {Value: mappedValue, : true, Enumerable: true, Configurable: true}, + // and false. + + // In browsers that support Object.defineProperty, use the following: + // Object.defineProperty(A, Pk, { value: mappedValue, writable: true, enumerable: true, configurable: true }); + + // For best browser support, use the following: + A[ k ] = mappedValue; + } + // d. Increase k by 1. + k++; + } + + // 9. return A + return A; + }; +} + +// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/every +if (!Array.prototype.every) { + Array.prototype.every = function(fun /*, thisp */) { + "use strict"; + + if (this == null) { + throw new TypeError(); + } + + var t = Object(this); + var len = t.length >>> 0; + if (typeof fun != "function") { + throw new TypeError(); + } + + var thisp = arguments[1]; + for (var i = 0; i < len; i++) { + if (i in t && !fun.call(thisp, t[i], i, t)) { + return false; + } + } + + return true; + }; +} + +// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/some +if (!Array.prototype.some) { + Array.prototype.some = function(fun /*, thisp */) { + "use strict"; + + if (this == null) { + throw new TypeError(); + } + + var t = Object(this); + var len = t.length >>> 0; + if (typeof fun != "function") { + throw new TypeError(); + } + + var thisp = arguments[1]; + for (var i = 0; i < len; i++) { + if (i in t && fun.call(thisp, t[i], i, t)) { + return true; + } + } + + return false; + }; +} + +// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind +if (!Function.prototype.bind) { + Function.prototype.bind = function (oThis) { + if (typeof this !== "function") { + // closest thing possible to the ECMAScript 5 internal IsCallable function + throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); + } + + var aArgs = Array.prototype.slice.call(arguments, 1), + fToBind = this, + fNOP = function () {}, + fBound = function () { + return fToBind.apply(this instanceof fNOP && oThis + ? this + : oThis, + aArgs.concat(Array.prototype.slice.call(arguments))); + }; + + fNOP.prototype = this.prototype; + fBound.prototype = new fNOP(); + + return fBound; + }; +} diff --git a/lib/type/Complex.js b/lib/type/Complex.js new file mode 100644 index 000000000..28fb03047 --- /dev/null +++ b/lib/type/Complex.js @@ -0,0 +1,367 @@ +var util = require('../util/index.js'), + + number = util.number, + isNumber = util.number.isNumber, + isString = util.string.isString; + +/** + * @constructor Complex + * + * A complex value can be constructed in the following ways: + * var a = new Complex(); + * var b = new Complex(re, im); + * var c = Complex.parse(str); + * + * Example usage: + * var a = new Complex(3, -4); // 3 - 4i + * a.re = 5; // a = 5 - 4i + * var i = a.im; // -4; + * var b = Complex.parse('2 + 6i'); // 2 + 6i + * var c = new Complex(); // 0 + 0i + * var d = math.add(a, b); // 5 + 2i + * + * @param {Number} re The real part of the complex value + * @param {Number} [im] The imaginary part of the complex value + */ +function Complex(re, im) { + if (!(this instanceof Complex)) { + throw new SyntaxError( + 'Complex constructor must be called with the new operator'); + } + + switch (arguments.length) { + case 0: + this.re = 0; + this.im = 0; + break; + + case 2: + if (!isNumber(re) || !isNumber(im)) { + throw new TypeError( + 'Two numbers expected in Complex constructor'); + } + this.re = re; + this.im = im; + break; + + default: + if (arguments.length != 0 && arguments.length != 2) { + throw new SyntaxError( + 'Two or zero arguments expected in Complex constructor'); + } + break; + } +} + +/** + * Test whether value is a Complex value + * @param {*} value + * @return {Boolean} isComplex + */ +Complex.isComplex = function isComplex(value) { + return (value instanceof Complex); +}; + +// private variables and functions for the parser +var text, index, c; + +function skipWhitespace() { + while (c == ' ' || c == '\t') { + next(); + } +} + +function isDigitDot (c) { + return ((c >= '0' && c <= '9') || c == '.'); +} + +function isDigit (c) { + return ((c >= '0' && c <= '9')); +} + +function next() { + index++; + c = text.charAt(index); +} + +function revert(oldIndex) { + index = oldIndex; + c = text.charAt(index); +} + +function parseNumber () { + var number = ''; + var oldIndex; + oldIndex = index; + + if (c == '+') { + next(); + } + else if (c == '-') { + number += c; + next(); + } + + if (!isDigitDot(c)) { + // a + or - must be followed by a digit + revert(oldIndex); + return null; + } + + // get number, can have a single dot + if (c == '.') { + number += c; + next(); + if (!isDigit(c)) { + // this is no legal number, it is just a dot + revert(oldIndex); + return null; + } + } + else { + while (isDigit(c)) { + number += c; + next(); + } + if (c == '.') { + number += c; + next(); + } + } + while (isDigit(c)) { + number += c; + next(); + } + + // check for scientific notation like "2.3e-4" or "1.23e50" + if (c == 'E' || c == 'e') { + number += c; + next(); + + if (c == '+' || c == '-') { + number += c; + next(); + } + + // Scientific notation MUST be followed by an exponent + if (!isDigit(c)) { + // this is no legal number, exponent is missing. + revert(oldIndex); + return null; + } + + while (isDigit(c)) { + number += c; + next(); + } + } + + return number; +} + +function parseComplex () { + // check for 'i', '-i', '+i' + var cnext = text.charAt(index + 1); + if (c == 'I' || c == 'i') { + next(); + return '1'; + } + else if ((c == '+' || c == '-') && (cnext == 'I' || cnext == 'i')) { + var number = (c == '+') ? '1' : '-1'; + next(); + next(); + return number; + } + + return null; +} + +/** + * Create a complex number from a provided real and imaginary number. + * When the imaginary part is zero, a real number is returned instead of + * a complex number. For example: + * Complex.create(2, 3); // returns a Complex(2, 3) + * Complex.create(2, 0); // returns a Number 2 + * + * @param {Number} re + * @param {Number} im + * @return {Complex | Number} value + */ +Complex.create = function create (re, im) { + if (im == 0) { + return re; + } + else { + return new Complex(re, im); + } +}; + +/** + * Parse a complex number from a string. For example Complex.parse("2 + 3i") + * will return a Complex value where re = 2, im = 3. + * Returns null if provided string does not contain a valid complex number. + * @param {String} str + * @returns {Complex | null} complex + */ +Complex.parse = function parse(str) { + text = str; + index = -1; + c = ''; + + if (!isString(text)) { + return null; + } + + next(); + skipWhitespace(); + var first = parseNumber(); + if (first) { + if (c == 'I' || c == 'i') { + // pure imaginary number + next(); + skipWhitespace(); + if (c) { + // garbage at the end. not good. + return null; + } + + return new Complex(0, Number(first)); + } + else { + // complex and real part + skipWhitespace(); + var separator = c; + if (separator != '+' && separator != '-') { + // pure real number + skipWhitespace(); + if (c) { + // garbage at the end. not good. + return null; + } + + return new Complex(Number(first), 0); + } + else { + // complex and real part + next(); + skipWhitespace(); + var second = parseNumber(); + if (second) { + if (c != 'I' && c != 'i') { + // 'i' missing at the end of the complex number + return null; + } + next(); + } + else { + second = parseComplex(); + if (!second) { + // imaginary number missing after separator + return null; + } + } + + if (separator == '-') { + if (second[0] == '-') { + second = '+' + second.substring(1); + } + else { + second = '-' + second; + } + } + + next(); + skipWhitespace(); + if (c) { + // garbage at the end. not good. + return null; + } + + return new Complex(Number(first), Number(second)); + } + } + } + else { + // check for 'i', '-i', '+i' + first = parseComplex(); + if (first) { + skipWhitespace(); + if (c) { + // garbage at the end. not good. + return null; + } + + return new Complex(0, Number(first)); + } + } + + return null; +}; + +/** + * Create a copy of the complex value + * @return {Complex} clone + */ +Complex.prototype.clone = function () { + return new Complex(this.re, this.im); +}; + +/** + * Get string representation of the Complex value + * @return {String} str + */ +Complex.prototype.toString = function () { + var str = ''; + var strRe = number.format(this.re); + var strIm = number.format(this.im); + + if (this.im == 0) { + // real value + str = strRe; + } + else if (this.re == 0) { + // purely complex value + if (this.im == 1) { + str = 'i'; + } + else if (this.im == -1) { + str = '-i'; + } + else { + str = strIm + 'i'; + } + } + else { + // complex value + if (this.im > 0) { + if (this.im == 1) { + str = strRe + ' + i'; + } + else { + str = strRe + ' + ' + strIm + 'i'; + } + } + else { + if (this.im == -1) { + str = strRe + ' - i'; + } + else { + str = strRe + ' - ' + + number.format(Math.abs(this.im)) + 'i'; + } + } + } + + return str; +}; + + +// exports +module.exports = Complex; + +// to trick my IDE which doesn't get it +exports.isComplex = Complex.isComplex; +exports.parse = Complex.parse; +exports.create = Complex.create; + +util.types.addType('complex', Complex); diff --git a/lib/type/Help.js b/lib/type/Help.js new file mode 100644 index 000000000..2d41afa33 --- /dev/null +++ b/lib/type/Help.js @@ -0,0 +1,92 @@ +var util = require('../util/index.js'), + object = util.object, + string = util.string; + +/** + * Documentation object + * @param {Object} math The math.js namespace + * @param {Object} doc Object containing properties: + * {String} name + * {String} category + * {String[]} syntax + * {String[]} examples + * {String[]} seealso + * @constructor + */ +function Help (math, doc) { + this.math = math; + this.doc = doc; +} + +/** + * Test whether a value is an instance of Help + * @param {*} value + * @return {Boolean} isHelp + */ +Help.isHelp = function isHelp (value) { + return (value instanceof Help); +}; + +/** + * Generate readable description from a Help object + * @return {String} readableDoc + * @private + */ +Help.prototype.toString = function () { + var doc = this.doc || {}; + var desc = '\n'; + + if (doc.name) { + desc += 'Name: ' + doc.name + '\n\n'; + } + if (doc.category) { + desc += 'Category: ' + doc.category + '\n\n'; + } + if (doc.description) { + desc += 'Description:\n ' + doc.description + '\n\n'; + } + if (doc.syntax) { + desc += 'Syntax:\n ' + doc.syntax.join('\n ') + '\n\n'; + } + if (doc.examples) { + var parser = this.math.parser(); + desc += 'Examples:\n'; + for (var i = 0; i < doc.examples.length; i++) { + var expr = doc.examples[i]; + var res; + try { + res = parser.eval(expr); + } + catch (e) { + res = e; + } + desc += ' ' + expr + '\n'; + if (res && !(res instanceof Help)) { + desc += ' ' + string.format(res) + '\n'; + } + } + desc += '\n'; + } + if (doc.seealso) { + desc += 'See also: ' + doc.seealso.join(', ') + '\n'; + } + + return desc; +}; + +// TODO: implement a toHTML function in Help + +/** + * Export the help object to JSON + */ +Help.prototype.toJSON = function () { + return object.extend({}, this.doc); +}; + +// exports +module.exports = Help; + +// to trick my IDE which doesn't get it +exports.isHelp = Help.isHelp; + +util.types.addType('help', Help); diff --git a/lib/type/Matrix.js b/lib/type/Matrix.js new file mode 100644 index 000000000..c6b8339ab --- /dev/null +++ b/lib/type/Matrix.js @@ -0,0 +1,680 @@ +var util = require('../util/index.js'), + Range = require('./Range.js'), + + number = util.number, + string = util.string, + array = util.array, + object = util.object; + +/** + * @constructor Matrix + * + * A Matrix is a wrapper around an Array. A matrix can hold a multi dimensional + * array. A matrix can be constructed as: + * var matrix = new Matrix(data) + * + * Matrix contains the functions to resize, get and set values, get the size, + * clone the matrix and to convert the matrix to a vector, array, or scalar. + * Furthermore, one can iterate over the matrix using map and forEach. + * The internal Array of the Matrix can be accessed using the method valueOf. + * + * Example usage: + * var matrix = new Matrix([[1, 2], [3, 4]); + * matix.size(); // [2, 2] + * matrix.resize([3, 2], 5); + * matrix.valueOf(); // [[1, 2], [3, 4], [5, 5]] + * matrix.get([1,2]) // 3 (indexes are zero-based) + * + * @param {Array | Matrix} [data] A multi dimensional array + */ +function Matrix(data) { + if (!(this instanceof Matrix)) { + throw new SyntaxError( + 'Matrix constructor must be called with the new operator'); + } + + if (data instanceof Matrix || data instanceof Range) { + // clone data from a Matrix or Range + this._data = data.toArray(); + } + else if (Array.isArray(data)) { + // use array as is + this._data = data; + } + else if (data != null) { + // unsupported type + throw new TypeError('Unsupported type of data (' + util.types.type(data) + ')'); + } + else { + // nothing provided + this._data = []; + } + + // verify the size of the array + this._size = array.size(this._data); +} + +/** + * Test whether an object is a Matrix + * @param {*} object + * @return {Boolean} isMatrix + */ +Matrix.isMatrix = function (object) { + return (object instanceof Matrix); +}; + +/** + * Get a value or a submatrix of the matrix. + * @param {Array | Matrix} index Zero-based index + */ +Matrix.prototype.get = function (index) { + var isScalar; + if (index instanceof Matrix) { + // index is scalar when size==[n] or size==[1,1,...] + isScalar = (index.size().length == 1) || !index.size().some(function (i) { + return (i != 0); + }); + index = index.valueOf(); + } + else if (Array.isArray(index)) { + isScalar = !index.some(function (elem) { + var size = array.size(elem.valueOf()); + return (size.length != 0) && (size != [0]); + }); + } + else { + throw new TypeError('Invalid index'); + } + + if (index.length != this._size.length) { + throw new RangeError('Dimension mismatch ' + + '(' + index.length + ' != ' + this._size.length + ')'); + } + + if (isScalar) { + // return a single value + switch (index.length) { + case 1: return _get(this._data, index[0]); + case 2: return _get(_get(this._data, index[0]), index[1]); + default: return _getScalar(this._data, index); + } + } + else { + // return a submatrix + switch (index.length) { + case 1: return new Matrix(_getSubmatrix1D(this._data, index)); + case 2: return new Matrix(_getSubmatrix2D(this._data, index)); + default: return new Matrix(_getSubmatrix(this._data, index, 0)); + } + // TODO: more efficient when creating an empty matrix and setting _data and _size manually + } +}; + +/** + * Get a single value from an array. The method tests whether: + * - index is a non-negative integer + * - index does not exceed the dimensions of array + * @param {Array} arr + * @param {Number} index Zero-based index + * @return {*} value + * @private + */ +function _get (arr, index) { + array.validateIndex(index, arr.length); + return arr[index]; // zero-based index +} + +/** + * Get a single value from the matrix. The value will be a copy of the original + * value in the matrix. + * Index is not checked for correct number of dimensions. + * @param {Array} data + * @param {Number[]} index Zero-based index + * @return {*} scalar + * @private + */ +function _getScalar (data, index) { + index.forEach(function (i) { + data = _get(data, i); + }); + return object.clone(data); +} + +/** + * Get a submatrix of a zero dimensional matrix. + * Index is not checked for correct number of dimensions. + * @param {Array} data + * @param {Array} index Zero-based index + * @return {Array} submatrix + * @private + */ +function _getSubmatrix1D (data, index) { + var current = index[0]; + if (current.map) { + // array or Range + return current.map(function (i) { + return _get(data, i); + }); + } + else { + // scalar + return [ + _get(data, current) + ]; + } +} + +/** + * Get a submatrix of a 2 dimensional matrix. + * Index is not checked for correct number of dimensions. + * @param {Array} data + * @param {Array} index Zero-based index + * @return {Array} submatrix + * @private + */ +function _getSubmatrix2D (data, index) { + var rows = index[0]; + var cols = index[1]; + + if (rows.map) { + if (cols.map) { + return rows.map(function (row) { + var child = _get(data, row); + return cols.map(function (col) { + return _get(child, col); + }); + }); + } + else { + return rows.map(function (row) { + return [ + _get(_get(data, row), cols) + ]; + }); + } + } + else { + if (cols.map) { + var child = _get(data, rows); + return [ + cols.map(function (col) { + return _get(child, col); + }) + ] + } + else { + return [ + [ + _get(_get(data, rows), cols) + ] + ]; + } + } +} + +/** + * Get a submatrix of a multi dimensional matrix. + * Index is not checked for correct number of dimensions. + * @param {Array} data + * @param {Array} index Zero-based index + * @param {number} dim + * @return {Array} submatrix + * @private + */ +function _getSubmatrix (data, index, dim) { + var last = (dim == index.length - 1); + var current = index[dim]; + var recurse = function (i) { + var child = _get(data, i); + return last ? child : _getSubmatrix(child, index, dim + 1); + }; + + if (current.map) { + // array or Range + return current.map(recurse); + } + else { + // scalar + return [ + recurse(current) + ]; + } +} + +/** + * Replace a value or a submatrix in the matrix. + * Indexes are zero-based. + * @param {Array | Matrix} index zero-based index + * @param {*} submatrix + * @return {Matrix} itself + */ +Matrix.prototype.set = function (index, submatrix) { + var isScalar; + if (index instanceof Matrix) { + // index is scalar when size==[n] or size==[0,0,...] + isScalar = (index.size().length == 1) || !index.size().some(function (i) { + return (i != 0); + }); + index = index.valueOf(); + } + else if (Array.isArray(index)) { + isScalar = !index.some(function (elem) { + var size = array.size(elem.valueOf()); + return (size.length != 0) && (size != [0]); + }); + } + else { + throw new TypeError('Invalid index'); + } + + if (submatrix instanceof Matrix || submatrix instanceof Range) { + submatrix = submatrix.valueOf(); + } + + if (index.length < this._size.length) { + throw new RangeError('Dimension mismatch ' + + '(' + index.length + ' != ' + this._size.length + ')'); + } + + if (isScalar) { + // set a scalar + // check whether submatrix is no matrix/array + if (array.size(submatrix.valueOf()).length != 0) { + throw new TypeError('Scalar value expected'); + } + + switch (index.length) { + case 1: _setScalar1D(this._data, this._size, index, submatrix); break; + case 2: _setScalar2D(this._data, this._size, index, submatrix); break; + default: _setScalar(this._data, this._size, index, submatrix); break; + } + } + else { + // set a submatrix + var subsize = this._size.concat(); + _setSubmatrix (this._data, subsize, index, 0, submatrix); + if (!object.deepEqual(this._size, subsize)) { + _init(this._data); + this.resize(subsize); + } + } + + return this; +}; + +/** + * Replace a single value in an array. The method tests whether index is a + * non-negative integer + * @param {Array} arr + * @param {Number} index Zero-based index + * @param {*} value + * @private + */ +function _set (arr, index, value) { + array.validateIndex(index); + if (Array.isArray(value)) { + throw new TypeError('Dimension mismatch, value expected instead of array'); + } + arr[index] = value; // zero-based index +} + +/** + * Replace a single value in a multi dimensional matrix + * @param {Array} data + * @param {Number[]} size + * @param {Number[]} index Zero-based index + * @param {*} value + * @private + */ +function _setScalar (data, size, index, value) { + var resized = false; + if (index.length > size.length) { + // dimension added + resized = true; + } + + for (var i = 0; i < index.length; i++) { + var index_i = index[i]; + array.validateIndex(index_i); + if ((size[i] == null) || (index_i + 1 > size[i])) { + size[i] = index_i + 1; // size is index + 1 as index is zero-based + resized = true; + } + } + + if (resized) { + array.resize(data, size, 0); + } + + var len = size.length; + index.forEach(function (v, i) { + if (i < len - 1) { + data = data[v]; // zero-based index + } + else { + data[v] = value; // zero-based index + } + }); +} + +/** + * Replace a single value in a zero dimensional matrix + * @param {Array} data + * @param {Number[]} size + * @param {Number[]} index zero-based index + * @param {*} value + * @private + */ +function _setScalar1D (data, size, index, value) { + var row = index[0]; + array.validateIndex(row); + if (row + 1 > size[0]) { + array.resize(data, [row + 1], 0); // size is index + 1 as index is zero-based + size[0] = row + 1; + } + data[row] = value; // zero-based index +} + +/** + * Replace a single value in a two dimensional matrix + * @param {Array} data + * @param {Number[]} size + * @param {Number[]} index zero-based index + * @param {*} value + * @private + */ +function _setScalar2D (data, size, index, value) { + var row = index[0]; + var col = index[1]; + array.validateIndex(row); + array.validateIndex(col); + + var resized = false; + if (row + 1 > (size[0] || 0)) { + size[0] = row + 1; // size is index + 1 as index is zero-based + resized = true; + } + if (col + 1 > (size[1] || 0)) { + size[1] = col + 1; // size is index + 1 as index is zero-based + resized = true; + } + if (resized) { + array.resize(data, size, 0); + } + + data[row][col] = value; // zero-based index +} + +/** + * Replace a submatrix of a multi dimensional matrix. + * @param {Array} data + * @param {Array} size + * @param {Array} index zero-based index + * @param {number} dim + * @param {Array} submatrix + * @private + */ +function _setSubmatrix (data, size, index, dim, submatrix) { + var last = (dim == index.length - 1); + var current = index[dim]; + var recurse = function (dataIndex, subIndex) { + if (last) { + _set(data, dataIndex, submatrix[subIndex]); + if (dataIndex + 1 > (size[dim] || 0)) { + size[dim] = dataIndex + 1; + } + } + else { + var child = data[dataIndex]; // zero-based index + if (!Array.isArray(child)) { + data[dataIndex] = child = [child]; // zero-based index + } + if (dataIndex + 1 > (size[dim] || 0)) { + size[dim] = dataIndex + 1; + } + _setSubmatrix(child, size, index, dim + 1, submatrix[subIndex]); + } + }; + + if (current.map) { + // array or Range + var len = (current.size && current.size() || current.length); + if (len != submatrix.length) { + throw new RangeError('Dimensions mismatch ' + + '(' + len + ' != '+ submatrix.length + ')'); + } + current.map(recurse); + } + else { + // scalar + recurse(current, 0) + } +} + +/** + * Recursively initialize all undefined values in the array with zeros + * @param array + * @private + */ +function _init(array) { + for (var i = 0, len = array.length; i < len; i++) { + var value = array[i]; + if (Array.isArray(value)) { + _init(value); + } + else if (value == undefined) { + array[i] = 0; + } + } +} + +/** + * Resize the matrix + * @param {Number[]} size + * @param {*} [defaultValue] Default value, filled in on new entries. + * If not provided, the matrix will be filled + * with zeros. + */ +Matrix.prototype.resize = function (size, defaultValue) { + array.resize(this._data, size, defaultValue); + this._size = object.clone(size); +}; + +/** + * Create a clone of the matrix + * @return {Matrix} clone + */ +Matrix.prototype.clone = function () { + var matrix = new Matrix(); + matrix._data = object.clone(this._data); + matrix._size = object.clone(this._size); + return matrix; +}; + +/** + * Retrieve the size of the matrix. + * The size of the matrix will be validated too + * @returns {Number[]} size + */ +Matrix.prototype.size = function () { + return this._size; +}; + +/** + * Create a new matrix with the results of the callback function executed on + * each entry of the matrix. + * @param {function} callback The callback method is invoked with three + * parameters: the value of the element, the index + * of the element, and the Matrix being traversed. + * @return {Matrix} matrix + */ +Matrix.prototype.map = function (callback) { + var me = this; + var matrix = new Matrix(); + var index = []; + var recurse = function (value, dim) { + if (Array.isArray(value)) { + return value.map(function (child, i) { + index[dim] = i; // zero-based index + return recurse(child, dim + 1); + }); + } + else { + return callback(value, index, me); + } + }; + matrix._data = recurse(this._data, 0); + matrix._size = object.clone(this._size); + + return matrix; +}; + +/** + * Execute a callback method on each entry of the matrix. + * @param {function} callback The callback method is invoked with three + * parameters: the value of the element, the index + * of the element, and the Matrix being traversed. + */ +Matrix.prototype.forEach = function (callback) { + var me = this; + var index = []; + var recurse = function (value, dim) { + if (Array.isArray(value)) { + value.forEach(function (child, i) { + index[dim] = i; // zero-based index + recurse(child, dim + 1); + }); + } + else { + callback(value, index, me); + } + }; + recurse(this._data, 0); +}; + +/** + * Create a scalar with a copy of the data of the Matrix + * Will return null if the matrix does not consist of a scalar value + * @return {* | null} scalar + */ +Matrix.prototype.toScalar = function () { + var scalar = this._data; + while (Array.isArray(scalar) && scalar.length == 1) { + scalar = scalar[0]; + } + + if (Array.isArray(scalar)) { + return null; + } + else { + return object.clone(scalar); + } +}; + +/** + * Test whether the matrix is a scalar. + * @return {boolean} isScalar + */ +Matrix.prototype.isScalar = function () { + return this._size.every(function (s) { + return (s <= 1); + }); +}; + +/** + * Create a vector with a copy of the data of the Matrix + * Returns null if the Matrix does not contain a vector + * + * A matrix is a vector when it has 0 or 1 dimensions, or has multiple + * dimensions where maximum one of the dimensions has a size larger than 1. + * return {Array | null} vector + */ +Matrix.prototype.toVector = function () { + var count = 0; + var dim = undefined; + var index = []; + this._size.forEach(function (length, i) { + if (length > 1) { + count++; + dim = i; + } + index[i] = 0; + }); + + if (count == 0) { + // scalar or empty + var scalar = this.toScalar(); + if (scalar) { + return [scalar]; + } + else { + return []; + } + } + else if (count == 1) { + // valid vector + var vector = []; + var recurse = function (data) { + if (Array.isArray(data)) { + data.forEach(recurse); + } + else { + vector.push(data); + } + }; + recurse(this._data); + return vector; + } + else { + // count > 1, this is no vector + return null; + } +}; + +/** + * Test if the matrix contains a vector. + * A matrix is a vector when it has 0 or 1 dimensions, or has multiple + * dimensions where maximum one of the dimensions has a size larger than 1. + * return {boolean} isVector + */ +Matrix.prototype.isVector = function () { + var count = 0; + this._size.forEach(function (length) { + if (length > 1) { + count++; + } + }); + return (count <= 1); +}; + +/** + * Create an Array with a copy of the data of the Matrix + * @returns {Array} array + */ +Matrix.prototype.toArray = function () { + return object.clone(this._data); +}; + +/** + * Get the primitive value of the Matrix: a multidimensional array + * @returns {Array} array + */ +Matrix.prototype.valueOf = function () { + return this._data; +}; + +/** + * Get a string representation of the matrix + * @returns {String} str + */ +Matrix.prototype.toString = function () { + return string.format(this._data); +}; + +// exports +module.exports = Matrix; + +// to trick my IDE which doesn't get it +exports.isMatrix = Matrix.isMatrix; + +util.types.addType('matrix', Matrix); diff --git a/lib/type/Range.js b/lib/type/Range.js new file mode 100644 index 000000000..46c8329b5 --- /dev/null +++ b/lib/type/Range.js @@ -0,0 +1,255 @@ +var util = require('../util/index.js'), + + number = util.number, + string = util.string, + array = util.array; + +/** + * @constructor Range + * Create a range. A range works similar to an Array, with functions like + * forEach and map. However, a Range object is very cheap to create compared to + * a large Array with indexes, as it stores only a start, step and end value of + * the range. + * + * A range can be constructed as: + * var range = new Range(start, end); + * var range = new Range(start, end, step); + * + * To get the result of the range: + * range.forEach(function (x) { + * console.log(x); + * }); + * range.map(function (x) { + * return math.sin(x); + * }); + * range.toArray(); + * + * Example usage: + * var c = new Range(2, 6); // 2:1:5 + * c.toArray(); // [2, 3, 4, 5] + * var d = new Range(2, -3, -1); // 2:-1:-2 + * d.toArray(); // [2, 1, 0, -1, -2] + * + * @param {Number} start included lower bound + * @param {Number} end excluded upper bound + * @param {Number} [step] step size, default value is 1 + */ +function Range(start, end, step) { + if (!(this instanceof Range)) { + throw new SyntaxError( + 'Range constructor must be called with the new operator'); + } + + if (start != null && !number.isNumber(start)) { + throw new TypeError('Parameter start must be a number'); + } + if (end != null && !number.isNumber(end)) { + throw new TypeError('Parameter end must be a number'); + } + if (step != null && !number.isNumber(step)) { + throw new TypeError('Parameter step must be a number'); + } + + this.start = (start != null) ? start : 0; + this.end = (end != null) ? end : 0; + this.step = (step != null) ? step : 1; +} + +/** + * Parse a string into a range, + * The string contains the start, optional step, and end, separated by a colon. + * If the string does not contain a valid range, null is returned. + * For example str='0:2:11'. + * @param {String} str + * @return {Range | null} range + */ +Range.parse = function parse (str) { + if (!string.isString(str)) { + return null; + } + + var args = str.split(':'); + var nums = args.map(function (arg) { + return Number(arg); + }); + + var invalid = nums.some(function (num) { + return isNaN(num); + }); + if(invalid) { + return null; + } + + switch (nums.length) { + case 2: return new Range(nums[0], nums[1]); + case 3: return new Range(nums[0], nums[2], nums[1]); + default: return null; + } +}; + +/** + * Create a clone of the range + * @return {Range} clone + */ +Range.prototype.clone = function () { + return new Range(this.start, this.end, this.step); +}; + +/** + * Test whether an object is a Range + * @param {*} object + * @return {Boolean} isRange + */ +Range.isRange = function isRange(object) { + return (object instanceof Range); +}; + +/** + * Retrieve the size of the range. + * @returns {Number[]} size + */ +Range.prototype.size = function () { + var len = 0, + start = Number(this.start), + step = Number(this.step), + end = Number(this.end), + diff = end - start; + + if (number.sign(step) == number.sign(diff)) { + len = Math.floor((diff) / step); + } + else if (diff == 0) { + len = 0; + } + + if (isNaN(len)) { + len = 0; + } + return [len]; +}; + +/** + * Execute a callback function for each value in the range. + * @param {function} callback The callback method is invoked with three + * parameters: the value of the element, the index + * of the element, and the Matrix being traversed. + */ +Range.prototype.forEach = function (callback) { + var x = Number(this.start); + var step = Number(this.step); + var end = Number(this.end); + var i = 0; + + if (step > 0) { + while (x < end) { + callback(x, i, this); + x += step; + i++; + } + } + else if (step < 0) { + while (x > end) { + callback(x, i, this); + x += step; + i++; + } + } +}; + +/** + * Execute a callback function for each value in the Range, and return the + * results as an array + * @param {function} callback The callback method is invoked with three + * parameters: the value of the element, the index + * of the element, and the Matrix being traversed. + * @returns {Array} array + */ +Range.prototype.map = function (callback) { + var array = []; + this.forEach(function (value, index, obj) { + array[index] = callback(value, index, obj); + }); + return array; +}; + +/** + * Create an Array with a copy of the Ranges data + * @returns {Array} array + */ +Range.prototype.toArray = function () { + var array = []; + this.forEach(function (value, index) { + array[index] = value; + }); + return array; +}; + +/** + * Create an array with a copy of the Ranges data. + * This method is equal to Range.toArray. + * @return {Array} vector + */ +Range.prototype.toVector = Range.prototype.toArray; + +/** + * Test if the range contains a vector. For a range, this is always the case + * return {boolean} isVector + */ +Range.prototype.isVector = function () { + return true; +}; + +/** + * Create a scalar with a copy of the data of the Range + * Will return null if the range does not consist of a scalar value + * @return {* | null} scalar + */ +Range.prototype.toScalar = function () { + var array = this.toArray(); + if (array.length == 1) { + return array[0]; + } + else { + return null; + } +}; + +/** + * Test whether the matrix is a scalar. + * @return {boolean} isScalar + */ +Range.prototype.isScalar = function () { + return (this.size()[0] == 1); +}; + +/** + * Get the primitive value of the Range, a one dimensional array + * @returns {Array} array + */ +Range.prototype.valueOf = function () { + // TODO: implement a caching mechanism for range.valueOf() + return this.toArray(); +}; + +/** + * Get the string representation of the range, for example '2:6' or '0:0.2:11' + * @returns {String} str + */ +Range.prototype.toString = function () { + var str = number.format(Number(this.start)); + if (this.step != 1) { + str += ':' + number.format(Number(this.step)); + } + str += ':' + number.format(Number(this.end)); + return str; +}; + + +// exports +module.exports = Range; + +// to trick my IDE which doesn't get it +exports.isRange = Range.isRange; +exports.parse = Range.parse; + +util.types.addType('range', Range); diff --git a/lib/type/Unit.js b/lib/type/Unit.js new file mode 100644 index 000000000..5e4b9b6f2 --- /dev/null +++ b/lib/type/Unit.js @@ -0,0 +1,725 @@ +var util = require('../util/index.js'), + + number = util.number, + string = util.string, + isNumber = util.number.isNumber, + isString = util.string.isString; + +/** + * @constructor Unit + * + * A unit can be constructed in the following ways: + * var a = new Unit(value, unit); + * var b = new Unit(null, unit); + * var c = Unit.parse(str); + * + * Example usage: + * var a = new Unit(5, 'cm'); // 50 mm + * var b = Unit.parse('23 kg'); // 23 kg + * var c = math.in(a, new Unit(null, 'm'); // 0.05 m + * + * @param {Number} [value] A value like 5.2 + * @param {String} [unit] A unit like "cm" or "inch" + */ +function Unit(value, unit) { + if (!(this instanceof Unit)) { + throw new Error('Unit constructor must be called with the new operator'); + } + + if (value != null && !isNumber(value)) { + throw new TypeError('First parameter in Unit constructor must be a number'); + } + if (unit != null && !isString(unit)) { + throw new TypeError('Second parameter in Unit constructor must be a string'); + } + + if (unit != null) { + // find the unit and prefix from the string + var res = _findUnit(unit); + if (!res) { + throw new SyntaxError('String "' + unit + '" is no unit'); + } + this.unit = res.unit; + this.prefix = res.prefix; + } + else { + this.unit = UNIT_NONE; + this.prefix = PREFIX_NONE; // link to a list with supported prefixes + } + + if (value != null) { + this.value = this._normalize(value); + this.fixPrefix = false; // is set true by the methods Unit.in and math.in + } + else { + this.value = null; + this.fixPrefix = true; + } +} + +// private variables and functions for the Unit parser +var text, index, c; + +function skipWhitespace() { + while (c == ' ' || c == '\t') { + next(); + } +} + +function isDigitDot (c) { + return ((c >= '0' && c <= '9') || c == '.'); +} + +function isDigit (c) { + return ((c >= '0' && c <= '9')); +} + +function next() { + index++; + c = text.charAt(index); +} + +function revert(oldIndex) { + index = oldIndex; + c = text.charAt(index); +} + +function parseNumber () { + var number = ''; + var oldIndex; + oldIndex = index; + + if (c == '+') { + next(); + } + else if (c == '-') { + number += c; + next(); + } + + if (!isDigitDot(c)) { + // a + or - must be followed by a digit + revert(oldIndex); + return null; + } + + // get number, can have a single dot + if (c == '.') { + number += c; + next(); + if (!isDigit(c)) { + // this is no legal number, it is just a dot + revert(oldIndex); + return null; + } + } + else { + while (isDigit(c)) { + number += c; + next(); + } + if (c == '.') { + number += c; + next(); + } + } + while (isDigit(c)) { + number += c; + next(); + } + + // check for scientific notation like "2.3e-4" or "1.23e50" + if (c == 'E' || c == 'e') { + number += c; + next(); + + if (c == '+' || c == '-') { + number += c; + next(); + } + + // Scientific notation MUST be followed by an exponent + if (!isDigit(c)) { + // this is no legal number, exponent is missing. + revert(oldIndex); + return null; + } + + while (isDigit(c)) { + number += c; + next(); + } + } + + return number; +} + +function parseUnit() { + var unit = ''; + + skipWhitespace(); + while (c && c != ' ' && c != '\t') { + unit += c; + next(); + } + + return unit || null; +} + +/** + * Parse a string into a unit. Returns null if the provided string does not + * contain a valid unit. + * @param {String} str A string like "5.2 inch", "4e2 kg" + * @return {Unit | null} unit + */ +Unit.parse = function parse(str) { + text = str; + index = -1; + c = ''; + + if (!isString(text)) { + return null; + } + + next(); + skipWhitespace(); + var value = parseNumber(); + var unit; + if (value) { + unit = parseUnit(); + + next(); + skipWhitespace(); + if (c) { + // garbage at the end. not good. + return null; + } + + if (value && unit) { + return new Unit(Number(value), unit); + } + } + else { + unit = parseUnit(); + + next(); + skipWhitespace(); + if (c) { + // garbage at the end. not good. + return null; + } + + return new Unit(null, unit) + } + + return null; +}; + +/** + * Test whether value is of type Unit + * @param {*} value + * @return {Boolean} isUnit + */ +Unit.isUnit = function isUnit(value) { + return (value instanceof Unit); +}; + +/** + * create a copy of this unit + * @return {Unit} clone + */ +Unit.prototype.clone = function () { + var clone = new Unit(); + + for (var p in this) { + if (this.hasOwnProperty(p)) { + clone[p] = this[p]; + } + } + + return clone; +}; + +/** + * Normalize a value, based on its currently set unit + * @param {Number} value + * @return {Number} normalized value + * @private + */ +Unit.prototype._normalize = function(value) { + return (value + this.unit.offset) * + this.unit.value * this.prefix.value; +}; + +/** + * Unnormalize a value, based on its currently set unit + * @param {Number} value + * @param {Number} [prefixValue] Optional prefix value to be used + * @return {Number} unnormalized value + * @private + */ +Unit.prototype._unnormalize = function (value, prefixValue) { + if (prefixValue == undefined) { + return value / this.unit.value / this.prefix.value - + this.unit.offset; + } + else { + return value / this.unit.value / prefixValue - + this.unit.offset; + } +}; + +/** + * Find a unit from a string + * @param {String} str A string like 'cm' or 'inch' + * @returns {Object | null} result When found, an object with fields unit and + * prefix is returned. Else, null is returned. + * @private + */ +function _findUnit(str) { + for (var i = 0, iMax = UNITS.length; i < iMax; i++) { + var UNIT = UNITS[i]; + + if (string.endsWith(str, UNIT.name) ) { + var prefixLen = (str.length - UNIT.name.length); + var prefixName = str.substring(0, prefixLen); + var prefix = UNIT.prefixes[prefixName]; + if (prefix !== undefined) { + // store unit, prefix, and value + return { + unit: UNIT, + prefix: prefix + }; + } + } + } + + return null; +} + +/** + * Test if the given expression is a unit. + * The unit can have a prefix but cannot have a value. + * @param {String} unit A plain unit without value. Can have prefix, like "cm" + * @return {Boolean} true if the given string is a unit + */ +Unit.isPlainUnit = function (unit) { + return (_findUnit(unit) != null); +}; + +/** + * check if this unit has given base unit + * @param {BASE_UNITS | undefined} base + */ +Unit.prototype.hasBase = function(base) { + if (this.unit.base === undefined) { + return (base === undefined); + } + return (this.unit.base === base); +}; + +/** + * Check if this unit has a base equal to another base + * @param {Unit} other + * @return {Boolean} true if equal base + */ +Unit.prototype.equalBase = function(other) { + return (this.unit.base === other.unit.base); +}; + +/** + * Check if this unit equals another unit + * @param {Unit} other + * @return {Boolean} true if both units are equal + */ +Unit.prototype.equals = function(other) { + return (this.equalBase(other) && this.value == other.value); +}; + +/** + * Create a clone of this unit with a representation + * @param {String | Unit} plainUnit A plain unit, without value. Can have prefix, like "cm" + * @returns {Unit} unit having fixed, specified unit + */ +Unit.prototype['in'] = function (plainUnit) { + var other; + if (isString(plainUnit)) { + other = new Unit(null, plainUnit); + + if (!this.equalBase(other)) { + throw new Error('Units do not match'); + } + + other.value = this.value; + return other; + } + else if (plainUnit instanceof Unit) { + if (!this.equalBase(plainUnit)) { + throw new Error('Units do not match'); + } + if (plainUnit.value != null) { + throw new Error('Cannot convert to a unit with a value'); + } + if (plainUnit.unit == null) { + throw new Error('Unit expected on the right hand side of function in'); + } + + other = plainUnit.clone(); + other.value = this.value; + other.fixPrefix = true; + return other; + } + else { + throw new Error('String or Unit expected as parameter'); + } +}; + +/** + * Return the value of the unit when represented with given plain unit + * @param {String | Unit} plainUnit For example 'cm' or 'inch' + * @return {Number} value + */ +Unit.prototype.toNumber = function (plainUnit) { + var other = this['in'](plainUnit); + var prefix = this.fixPrefix ? other._bestPrefix() : other.prefix; + return other._unnormalize(other.value, prefix.value); +}; + +/** + * Get string representation + * @return {String} + */ +Unit.prototype.toString = function() { + var value, str; + if (!this.fixPrefix) { + var bestPrefix = this._bestPrefix(); + value = this._unnormalize(this.value, bestPrefix.value); + str = (this.value != null) ? number.format(value) + ' ' : ''; + str += bestPrefix.name + this.unit.name; + } + else { + value = this._unnormalize(this.value); + str = (this.value != null) ? number.format(value) + ' ' : ''; + str += this.prefix.name + this.unit.name; + } + return str; +}; + +/** + * Calculate the best prefix using current value. + * @returns {Object} prefix + * @private + */ +Unit.prototype._bestPrefix = function () { + // find the best prefix value (resulting in the value of which + // the absolute value of the log10 is closest to zero, + // though with a little offset of 1.2 for nicer values: you get a + // sequence 1mm 100mm 500mm 0.6m 1m 10m 100m 500m 0.6km 1km ... + var absValue = Math.abs(this.value / this.unit.value); + var bestPrefix = PREFIX_NONE; + var bestDiff = Math.abs( + Math.log(absValue / bestPrefix.value) / Math.LN10 - 1.2); + + var prefixes = this.unit.prefixes; + for (var p in prefixes) { + if (prefixes.hasOwnProperty(p)) { + var prefix = prefixes[p]; + if (prefix.scientific) { + var diff = Math.abs( + Math.log(absValue / prefix.value) / Math.LN10 - 1.2); + + if (diff < bestDiff) { + bestPrefix = prefix; + bestDiff = diff; + } + } + } + } + + return bestPrefix; +}; + +var PREFIXES = { + 'NONE': { + '': {'name': '', 'value': 1, 'scientific': true} + }, + 'SHORT': { + '': {'name': '', 'value': 1, 'scientific': true}, + + 'da': {'name': 'da', 'value': 1e1, 'scientific': false}, + 'h': {'name': 'h', 'value': 1e2, 'scientific': false}, + 'k': {'name': 'k', 'value': 1e3, 'scientific': true}, + 'M': {'name': 'M', 'value': 1e6, 'scientific': true}, + 'G': {'name': 'G', 'value': 1e9, 'scientific': true}, + 'T': {'name': 'T', 'value': 1e12, 'scientific': true}, + 'P': {'name': 'P', 'value': 1e15, 'scientific': true}, + 'E': {'name': 'E', 'value': 1e18, 'scientific': true}, + 'Z': {'name': 'Z', 'value': 1e21, 'scientific': true}, + 'Y': {'name': 'Y', 'value': 1e24, 'scientific': true}, + + 'd': {'name': 'd', 'value': 1e-1, 'scientific': false}, + 'c': {'name': 'c', 'value': 1e-2, 'scientific': false}, + 'm': {'name': 'm', 'value': 1e-3, 'scientific': true}, + // 'µ': {'name': 'µ', 'value': 1e-6, 'scientific': true}, + 'u': {'name': 'u', 'value': 1e-6, 'scientific': true}, + 'n': {'name': 'n', 'value': 1e-9, 'scientific': true}, + 'p': {'name': 'p', 'value': 1e-12, 'scientific': true}, + 'f': {'name': 'f', 'value': 1e-15, 'scientific': true}, + 'a': {'name': 'a', 'value': 1e-18, 'scientific': true}, + 'z': {'name': 'z', 'value': 1e-21, 'scientific': true}, + 'y': {'name': 'y', 'value': 1e-24, 'scientific': true} + }, + 'LONG': { + '': {'name': '', 'value': 1, 'scientific': true}, + + 'deca': {'name': 'deca', 'value': 1e1, 'scientific': false}, + 'hecto': {'name': 'hecto', 'value': 1e2, 'scientific': false}, + 'kilo': {'name': 'kilo', 'value': 1e3, 'scientific': true}, + 'mega': {'name': 'mega', 'value': 1e6, 'scientific': true}, + 'giga': {'name': 'giga', 'value': 1e9, 'scientific': true}, + 'tera': {'name': 'tera', 'value': 1e12, 'scientific': true}, + 'peta': {'name': 'peta', 'value': 1e15, 'scientific': true}, + 'exa': {'name': 'exa', 'value': 1e18, 'scientific': true}, + 'zetta': {'name': 'zetta', 'value': 1e21, 'scientific': true}, + 'yotta': {'name': 'yotta', 'value': 1e24, 'scientific': true}, + + 'deci': {'name': 'deci', 'value': 1e-1, 'scientific': false}, + 'centi': {'name': 'centi', 'value': 1e-2, 'scientific': false}, + 'milli': {'name': 'milli', 'value': 1e-3, 'scientific': true}, + 'micro': {'name': 'micro', 'value': 1e-6, 'scientific': true}, + 'nano': {'name': 'nano', 'value': 1e-9, 'scientific': true}, + 'pico': {'name': 'pico', 'value': 1e-12, 'scientific': true}, + 'femto': {'name': 'femto', 'value': 1e-15, 'scientific': true}, + 'atto': {'name': 'atto', 'value': 1e-18, 'scientific': true}, + 'zepto': {'name': 'zepto', 'value': 1e-21, 'scientific': true}, + 'yocto': {'name': 'yocto', 'value': 1e-24, 'scientific': true} + }, + 'BINARY_SHORT': { + '': {'name': '', 'value': 1, 'scientific': true}, + 'k': {'name': 'k', 'value': 1024, 'scientific': true}, + 'M': {'name': 'M', 'value': Math.pow(1024, 2), 'scientific': true}, + 'G': {'name': 'G', 'value': Math.pow(1024, 3), 'scientific': true}, + 'T': {'name': 'T', 'value': Math.pow(1024, 4), 'scientific': true}, + 'P': {'name': 'P', 'value': Math.pow(1024, 5), 'scientific': true}, + 'E': {'name': 'E', 'value': Math.pow(1024, 6), 'scientific': true}, + 'Z': {'name': 'Z', 'value': Math.pow(1024, 7), 'scientific': true}, + 'Y': {'name': 'Y', 'value': Math.pow(1024, 8), 'scientific': true}, + + 'Ki': {'name': 'Ki', 'value': 1024, 'scientific': true}, + 'Mi': {'name': 'Mi', 'value': Math.pow(1024, 2), 'scientific': true}, + 'Gi': {'name': 'Gi', 'value': Math.pow(1024, 3), 'scientific': true}, + 'Ti': {'name': 'Ti', 'value': Math.pow(1024, 4), 'scientific': true}, + 'Pi': {'name': 'Pi', 'value': Math.pow(1024, 5), 'scientific': true}, + 'Ei': {'name': 'Ei', 'value': Math.pow(1024, 6), 'scientific': true}, + 'Zi': {'name': 'Zi', 'value': Math.pow(1024, 7), 'scientific': true}, + 'Yi': {'name': 'Yi', 'value': Math.pow(1024, 8), 'scientific': true} + }, + 'BINARY_LONG': { + '': {'name': '', 'value': 1, 'scientific': true}, + 'kilo': {'name': 'kilo', 'value': 1024, 'scientific': true}, + 'mega': {'name': 'mega', 'value': Math.pow(1024, 2), 'scientific': true}, + 'giga': {'name': 'giga', 'value': Math.pow(1024, 3), 'scientific': true}, + 'tera': {'name': 'tera', 'value': Math.pow(1024, 4), 'scientific': true}, + 'peta': {'name': 'peta', 'value': Math.pow(1024, 5), 'scientific': true}, + 'exa': {'name': 'exa', 'value': Math.pow(1024, 6), 'scientific': true}, + 'zetta': {'name': 'zetta', 'value': Math.pow(1024, 7), 'scientific': true}, + 'yotta': {'name': 'yotta', 'value': Math.pow(1024, 8), 'scientific': true}, + + 'kibi': {'name': 'kibi', 'value': 1024, 'scientific': true}, + 'mebi': {'name': 'mebi', 'value': Math.pow(1024, 2), 'scientific': true}, + 'gibi': {'name': 'gibi', 'value': Math.pow(1024, 3), 'scientific': true}, + 'tebi': {'name': 'tebi', 'value': Math.pow(1024, 4), 'scientific': true}, + 'pebi': {'name': 'pebi', 'value': Math.pow(1024, 5), 'scientific': true}, + 'exi': {'name': 'exi', 'value': Math.pow(1024, 6), 'scientific': true}, + 'zebi': {'name': 'zebi', 'value': Math.pow(1024, 7), 'scientific': true}, + 'yobi': {'name': 'yobi', 'value': Math.pow(1024, 8), 'scientific': true} + } +}; + +var PREFIX_NONE = {'name': '', 'value': 1, 'scientific': true}; + +var BASE_UNITS = { + 'NONE': {}, + + 'LENGTH': {}, // meter + 'MASS': {}, // kilogram + 'TIME': {}, // second + 'CURRENT': {}, // ampere + 'TEMPERATURE': {}, // kelvin + 'LUMINOUS_INTENSITY': {}, // candela + 'AMOUNT_OF_SUBSTANCE': {}, // mole + + 'FORCE': {}, // Newton + 'SURFACE': {}, // m2 + 'VOLUME': {}, // m3 + 'ANGLE': {}, // rad + 'BIT': {} // bit (digital) +}; + +BASE_UNIT_NONE = {}; + +UNIT_NONE = {'name': '', 'base': BASE_UNIT_NONE, 'value': 1, 'offset': 0}; + +var UNITS = [ + // length + {'name': 'meter', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.LONG, 'value': 1, 'offset': 0}, + {'name': 'inch', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.0254, 'offset': 0}, + {'name': 'foot', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.3048, 'offset': 0}, + {'name': 'yard', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.9144, 'offset': 0}, + {'name': 'mile', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 1609.344, 'offset': 0}, + {'name': 'link', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.201168, 'offset': 0}, + {'name': 'rod', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 5.029210, 'offset': 0}, + {'name': 'chain', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 20.1168, 'offset': 0}, + {'name': 'angstrom', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 1e-10, 'offset': 0}, + + {'name': 'm', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.SHORT, 'value': 1, 'offset': 0}, + //{'name': 'in', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.0254, 'offset': 0}, not supported, In is an operator + {'name': 'ft', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.3048, 'offset': 0}, + {'name': 'yd', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.9144, 'offset': 0}, + {'name': 'mi', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 1609.344, 'offset': 0}, + {'name': 'li', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.201168, 'offset': 0}, + {'name': 'rd', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 5.029210, 'offset': 0}, + {'name': 'ch', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 20.1168, 'offset': 0}, + {'name': 'mil', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.0000254, 'offset': 0}, // 1/1000 inch + + // Surface + {'name': 'm2', 'base': BASE_UNITS.SURFACE, 'prefixes': PREFIXES.SHORT, 'value': 1, 'offset': 0}, + {'name': 'sqin', 'base': BASE_UNITS.SURFACE, 'prefixes': PREFIXES.NONE, 'value': 0.00064516, 'offset': 0}, // 645.16 mm2 + {'name': 'sqft', 'base': BASE_UNITS.SURFACE, 'prefixes': PREFIXES.NONE, 'value': 0.09290304, 'offset': 0}, // 0.09290304 m2 + {'name': 'sqyd', 'base': BASE_UNITS.SURFACE, 'prefixes': PREFIXES.NONE, 'value': 0.83612736, 'offset': 0}, // 0.83612736 m2 + {'name': 'sqmi', 'base': BASE_UNITS.SURFACE, 'prefixes': PREFIXES.NONE, 'value': 2589988.110336, 'offset': 0}, // 2.589988110336 km2 + {'name': 'sqrd', 'base': BASE_UNITS.SURFACE, 'prefixes': PREFIXES.NONE, 'value': 25.29295, 'offset': 0}, // 25.29295 m2 + {'name': 'sqch', 'base': BASE_UNITS.SURFACE, 'prefixes': PREFIXES.NONE, 'value': 404.6873, 'offset': 0}, // 404.6873 m2 + {'name': 'sqmil', 'base': BASE_UNITS.SURFACE, 'prefixes': PREFIXES.NONE, 'value': 6.4516e-10, 'offset': 0}, // 6.4516 * 10^-10 m2 + + // Volume + {'name': 'm3', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.SHORT, 'value': 1, 'offset': 0}, + {'name': 'L', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.SHORT, 'value': 0.001, 'offset': 0}, // litre + {'name': 'litre', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.LONG, 'value': 0.001, 'offset': 0}, + {'name': 'cuin', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 1.6387064e-5, 'offset': 0}, // 1.6387064e-5 m3 + {'name': 'cuft', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.028316846592, 'offset': 0}, // 28.316 846 592 L + {'name': 'cuyd', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.764554857984, 'offset': 0}, // 764.554 857 984 L + {'name': 'teaspoon', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.000005, 'offset': 0}, // 5 mL + {'name': 'tablespoon', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.000015, 'offset': 0}, // 15 mL + //{'name': 'cup', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.000240, 'offset': 0}, // 240 mL // not possible, we have already another cup + + // Liquid volume + {'name': 'minim', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.00000006161152, 'offset': 0}, // 0.06161152 mL + {'name': 'fluiddram', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0000036966911, 'offset': 0}, // 3.696691 mL + {'name': 'fluidounce', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.00002957353, 'offset': 0}, // 29.57353 mL + {'name': 'gill', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0001182941, 'offset': 0}, // 118.2941 mL + {'name': 'cup', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0002365882, 'offset': 0}, // 236.5882 mL + {'name': 'pint', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0004731765, 'offset': 0}, // 473.1765 mL + {'name': 'quart', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0009463529, 'offset': 0}, // 946.3529 mL + {'name': 'gallon', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.003785412, 'offset': 0}, // 3.785412 L + {'name': 'beerbarrel', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.1173478, 'offset': 0}, // 117.3478 L + {'name': 'oilbarrel', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.1589873, 'offset': 0}, // 158.9873 L + {'name': 'hogshead', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.2384810, 'offset': 0}, // 238.4810 L + + //{'name': 'min', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.00000006161152, 'offset': 0}, // 0.06161152 mL // min is already in use as minute + {'name': 'fldr', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0000036966911, 'offset': 0}, // 3.696691 mL + {'name': 'floz', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.00002957353, 'offset': 0}, // 29.57353 mL + {'name': 'gi', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0001182941, 'offset': 0}, // 118.2941 mL + {'name': 'cp', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0002365882, 'offset': 0}, // 236.5882 mL + {'name': 'pt', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0004731765, 'offset': 0}, // 473.1765 mL + {'name': 'qt', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0009463529, 'offset': 0}, // 946.3529 mL + {'name': 'gal', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.003785412, 'offset': 0}, // 3.785412 L + {'name': 'bbl', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.1173478, 'offset': 0}, // 117.3478 L + {'name': 'obl', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.1589873, 'offset': 0}, // 158.9873 L + //{'name': 'hogshead', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.2384810, 'offset': 0}, // 238.4810 L // TODO: hh? + + // Mass + {'name': 'g', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.SHORT, 'value': 0.001, 'offset': 0}, + {'name': 'gram', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.LONG, 'value': 0.001, 'offset': 0}, + + {'name': 'ton', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.SHORT, 'value': 907.18474, 'offset': 0}, + {'name': 'tonne', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.SHORT, 'value': 1000, 'offset': 0}, + + {'name': 'grain', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 64.79891e-6, 'offset': 0}, + {'name': 'dram', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 1.7718451953125e-3, 'offset': 0}, + {'name': 'ounce', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 28.349523125e-3, 'offset': 0}, + {'name': 'poundmass', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 453.59237e-3, 'offset': 0}, + {'name': 'hundredweight', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 45.359237, 'offset': 0}, + {'name': 'stick', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 115e-3, 'offset': 0}, + + {'name': 'gr', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 64.79891e-6, 'offset': 0}, + {'name': 'dr', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 1.7718451953125e-3, 'offset': 0}, + {'name': 'oz', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 28.349523125e-3, 'offset': 0}, + {'name': 'lbm', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 453.59237e-3, 'offset': 0}, + {'name': 'cwt', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 45.359237, 'offset': 0}, + + // Time + {'name': 's', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.SHORT, 'value': 1, 'offset': 0}, + {'name': 'min', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.NONE, 'value': 60, 'offset': 0}, + {'name': 'h', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.NONE, 'value': 3600, 'offset': 0}, + {'name': 'seconds', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.LONG, 'value': 1, 'offset': 0}, + {'name': 'second', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.LONG, 'value': 1, 'offset': 0}, + {'name': 'sec', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.LONG, 'value': 1, 'offset': 0}, + {'name': 'minutes', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.NONE, 'value': 60, 'offset': 0}, + {'name': 'minute', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.NONE, 'value': 60, 'offset': 0}, + {'name': 'hours', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.NONE, 'value': 3600, 'offset': 0}, + {'name': 'hour', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.NONE, 'value': 3600, 'offset': 0}, + {'name': 'day', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.NONE, 'value': 86400, 'offset': 0}, + {'name': 'days', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.NONE, 'value': 86400, 'offset': 0}, + + // Angles + {'name': 'rad', 'base': BASE_UNITS.ANGLE, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0}, + {'name': 'deg', 'base': BASE_UNITS.ANGLE, 'prefixes': PREFIXES.NONE, 'value': 0.017453292519943295769236907684888, 'offset': 0}, // deg = rad / (2*pi) * 360 = rad / 0.017453292519943295769236907684888 + {'name': 'grad', 'base': BASE_UNITS.ANGLE, 'prefixes': PREFIXES.NONE, 'value': 0.015707963267948966192313216916399, 'offset': 0}, // grad = rad / (2*pi) * 400 = rad / 0.015707963267948966192313216916399 + {'name': 'cycle', 'base': BASE_UNITS.ANGLE, 'prefixes': PREFIXES.NONE, 'value': 6.2831853071795864769252867665793, 'offset': 0}, // cycle = rad / (2*pi) = rad / 6.2831853071795864769252867665793 + + // Electric current + {'name': 'A', 'base': BASE_UNITS.CURRENT, 'prefixes': PREFIXES.SHORT, 'value': 1, 'offset': 0}, + {'name': 'ampere', 'base': BASE_UNITS.CURRENT, 'prefixes': PREFIXES.LONG, 'value': 1, 'offset': 0}, + + // Temperature + // K(C) = °C + 273.15 + // K(F) = (°F + 459.67) / 1.8 + // K(R) = °R / 1.8 + {'name': 'K', 'base': BASE_UNITS.TEMPERATURE, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0}, + {'name': 'degC', 'base': BASE_UNITS.TEMPERATURE, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 273.15}, + {'name': 'degF', 'base': BASE_UNITS.TEMPERATURE, 'prefixes': PREFIXES.NONE, 'value': 1/1.8, 'offset': 459.67}, + {'name': 'degR', 'base': BASE_UNITS.TEMPERATURE, 'prefixes': PREFIXES.NONE, 'value': 1/1.8, 'offset': 0}, + {'name': 'kelvin', 'base': BASE_UNITS.TEMPERATURE, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0}, + {'name': 'celsius', 'base': BASE_UNITS.TEMPERATURE, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 273.15}, + {'name': 'fahrenheit', 'base': BASE_UNITS.TEMPERATURE, 'prefixes': PREFIXES.NONE, 'value': 1/1.8, 'offset': 459.67}, + {'name': 'rankine', 'base': BASE_UNITS.TEMPERATURE, 'prefixes': PREFIXES.NONE, 'value': 1/1.8, 'offset': 0}, + + // amount of substance + {'name': 'mol', 'base': BASE_UNITS.AMOUNT_OF_SUBSTANCE, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0}, + {'name': 'mole', 'base': BASE_UNITS.AMOUNT_OF_SUBSTANCE, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0}, + + // luminous intensity + {'name': 'cd', 'base': BASE_UNITS.LUMINOUS_INTENSITY, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0}, + {'name': 'candela', 'base': BASE_UNITS.LUMINOUS_INTENSITY, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0}, + // TODO: units STERADIAN + //{'name': 'sr', 'base': BASE_UNITS.STERADIAN, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0}, + //{'name': 'steradian', 'base': BASE_UNITS.STERADIAN, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0}, + + // Force + {'name': 'N', 'base': BASE_UNITS.FORCE, 'prefixes': PREFIXES.SHORT, 'value': 1, 'offset': 0}, + {'name': 'newton', 'base': BASE_UNITS.FORCE, 'prefixes': PREFIXES.LONG, 'value': 1, 'offset': 0}, + {'name': 'lbf', 'base': BASE_UNITS.FORCE, 'prefixes': PREFIXES.NONE, 'value': 4.4482216152605, 'offset': 0}, + {'name': 'poundforce', 'base': BASE_UNITS.FORCE, 'prefixes': PREFIXES.NONE, 'value': 4.4482216152605, 'offset': 0}, + + // Binary + {'name': 'b', 'base': BASE_UNITS.BIT, 'prefixes': PREFIXES.BINARY_SHORT, 'value': 1, 'offset': 0}, + {'name': 'bits', 'base': BASE_UNITS.BIT, 'prefixes': PREFIXES.BINARY_LONG, 'value': 1, 'offset': 0}, + {'name': 'B', 'base': BASE_UNITS.BIT, 'prefixes': PREFIXES.BINARY_SHORT, 'value': 8, 'offset': 0}, + {'name': 'bytes', 'base': BASE_UNITS.BIT, 'prefixes': PREFIXES.BINARY_LONG, 'value': 8, 'offset': 0} +]; + +Unit.PREFIXES = PREFIXES; +Unit.BASE_UNITS = BASE_UNITS; +Unit.UNITS = UNITS; + + +// exports +module.exports = Unit; + +// to trick my IDE which doesn't get it +exports.isUnit = Unit.isUnit; +exports.isPlainUnit = Unit.isPlainUnit; +exports.parse = Unit.parse; + +util.types.addType('unit', Unit); diff --git a/lib/type/collection.js b/lib/type/collection.js new file mode 100644 index 000000000..f6b6101f1 --- /dev/null +++ b/lib/type/collection.js @@ -0,0 +1,228 @@ +var util = require('../util/index.js'), + + Matrix = require('./Matrix.js'), + Range = require('./Range.js'), + + isArray = Array.isArray, + isString = util.string.isString; + +// utility methods for strings, objects, and arrays + +/** + * Convert function arguments to an array. Arguments can have the following + * signature: + * fn() + * fn(n) + * fn(m, n, p, ...) + * fn([m, n, p, ...]) + * @param {...Number | Array | Matrix} args + * @returns {Array} array + */ +exports.argsToArray = function argsToArray(args) { + var array; + if (args.length == 0) { + // fn() + array = []; + } + else if (args.length == 1) { + // fn(n) + // fn([m, n, p, ...]) + array = args[0]; + if (array instanceof Matrix) { + array = array.toVector(); + } + if (array instanceof Range) { + array = array.valueOf(); + } + if (!isArray(array)) { + array = [array]; + } + } + else { + // fn(m, n, p, ...) + /* TODO: cleanup + array = []; + for (var i = 0; i < args.length; i++) { + array[i] = args[i]; + } + */ + array = Array.prototype.slice.apply(args); + } + return array; +}; + + +/** + * Test whether a value is a collection: an Array, Matrix, or Range + * @param {*} x + * @returns {boolean} isCollection + */ +exports.isCollection = function isCollection (x) { + return (isArray(x) || (x instanceof Matrix) || (x instanceof Range)); +}; + +// TODO: write the map, deepMap, map2, and deepMap2 functions in a more concise way + +/** + * Execute function fn element wise for each element in array. + * Returns an array with the results + * @param {Array | Matrix | Range} array + * @param {function} fn + * @return {Array | Matrix} res + */ +exports.map = function map(array, fn) { + if (array && array.map) { + return array.map(function (x) { + return fn(x); + }); + } + else { + throw new TypeError('Array expected'); + } +}; + +/** + * Execute function fn element wise for each element in array and any nested + * array + * Returns an array with the results + * @param {Array | Matrix | Range} array + * @param {function} fn + * @return {Array | Matrix} res + */ +exports.deepMap = function deepMap(array, fn) { + if (array && array.map) { + return array.map(function (x) { + return deepMap(x, fn); + }); + } + else { + return fn(array); + } +}; + +/** + * Execute function fn element wise for each entry in two given arrays, or + * for a (scalar) object and array pair. Returns an array with the results + * @param {Array | Matrix | Range | Object} array1 + * @param {Array | Matrix | Range | Object} array2 + * @param {function} fn + * @return {Array | Matrix} res + */ +exports.map2 = function map2(array1, array2, fn) { + var res, len, i; + + // handle Matrix + if (array1 instanceof Matrix || array2 instanceof Matrix) { + return new Matrix(map2(array1.valueOf(), array2.valueOf(), fn)); + } + + // handle Range + if (array1 instanceof Range || array2 instanceof Range) { + // TODO: exports.map2 does not utilize Range.map + return map2(array1.valueOf(), array2.valueOf(), fn); + } + + if (isArray(array1)) { + if (isArray(array2)) { + // fn(array, array) + if (array1.length != array2.length) { + throw new RangeError('Dimension mismatch ' + + '(' + array1.length + ' != ' + array2.length + ')'); + } + + res = []; + len = array1.length; + for (i = 0; i < len; i++) { + res[i] = fn(array1[i], array2[i]); + } + } + else { + // fn(array, object) + res = []; + len = array1.length; + for (i = 0; i < len; i++) { + res[i] = fn(array1[i], array2); + } + } + } + else { + if (isArray(array2)) { + // fn(object, array) + res = []; + len = array2.length; + for (i = 0; i < len; i++) { + res[i] = fn(array1, array2[i]); + } + } + else { + // fn(object, object) + res = fn(array1, array2); + } + } + + return res; +}; + +/** + * Execute function fn element wise for each entry in two given arrays, + * and for any nested array. Objects can also be scalar objects. + * Returns an array with the results. + * @param {Array | Matrix | Range | Object} array1 + * @param {Array | Matrix | Range | Object} array2 + * @param {function} fn + * @return {Array | Matrix} res + */ +exports.deepMap2 = function deepMap2(array1, array2, fn) { + var res, len, i; + + // handle Matrix + if (array1 instanceof Matrix || array2 instanceof Matrix) { + return new Matrix(deepMap2(array1.valueOf(), array2.valueOf(), fn)); + } + + // handle Range + if (array1 instanceof Range || array2 instanceof Range) { + // TODO: util.deepMap2 does not utilize Range.map + return deepMap2(array1.valueOf(), array2.valueOf(), fn); + } + + if (isArray(array1)) { + if (isArray(array2)) { + // fn(array, array) + if (array1.length != array2.length) { + throw new RangeError('Dimension mismatch ' + + '(' + array1.length + ' != ' + array2.length + ')'); + } + + res = []; + len = array1.length; + for (i = 0; i < len; i++) { + res[i] = deepMap2(array1[i], array2[i], fn); + } + } + else { + // fn(array, object) + res = []; + len = array1.length; + for (i = 0; i < len; i++) { + res[i] = deepMap2(array1[i], array2, fn); + } + } + } + else { + if (isArray(array2)) { + // fn(object, array) + res = []; + len = array2.length; + for (i = 0; i < len; i++) { + res[i] = deepMap2(array1, array2[i], fn); + } + } + else { + // fn(object, object) + res = fn(array1, array2); + } + } + + return res; +}; diff --git a/lib/type/index.js b/lib/type/index.js new file mode 100644 index 000000000..1b1021889 --- /dev/null +++ b/lib/type/index.js @@ -0,0 +1,7 @@ +exports.Complex = require('./Complex.js'); +exports.Range = require('./Range.js'); +exports.Matrix = require('./Matrix.js'); +exports.Unit = require('./Unit.js'); +exports.Help = require('./Help.js'); + +exports.collection = require('./collection.js'); diff --git a/lib/util/array.js b/lib/util/array.js new file mode 100644 index 000000000..368221c7c --- /dev/null +++ b/lib/util/array.js @@ -0,0 +1,221 @@ +var number = require('./number'), + string = require('./string'), + object = require('./object'), + types = require('./types'); + +/** + * Recursively calculate the size of a multi dimensional array. + * @param {Array} x + * @Return {Number[]} size + * @private + */ +function _size(x) { + if (Array.isArray(x)) { + var len = x.length; + + var size = len ? _size(x[0]) : []; + size.unshift(len); + return size; + } + else { + return []; + } +} + +/** + * Calculate the size of a multi dimensional array. + * All elements in the array are checked for matching dimensions using the + * method validate + * @param {Array} x + * @Return {Number[]} size + * @throws RangeError + */ +exports.size = function size (x) { + // calculate the size + var s = _size(x); + + // verify the size + exports.validate(x, s); + + return s; +}; + +/** + * Recursively validate whether each element in a multi dimensional array + * has a size corresponding to the provided size array. + * @param {Array} array Array to be validated + * @param {Number[]} size Array with the size of each dimension + * @param {Number} dim Current dimension + * @throws RangeError + * @private + */ +function _validate(array, size, dim) { + var i; + var len = array.length; + + if (len != size[dim]) { + throw new RangeError('Dimension mismatch (' + len + ' != ' + size[dim] + ')'); + } + + if (dim < size.length - 1) { + // recursively validate each child array + var dimNext = dim + 1; + for (i = 0; i < len; i++) { + var child = array[i]; + if (!Array.isArray(child)) { + throw new RangeError('Dimension mismatch ' + + '(' + (size.length - 1) + ' < ' + size.length + ')'); + } + _validate(array[i], size, dimNext); + } + } + else { + // last dimension. none of the childs may be an array + for (i = 0; i < len; i++) { + if (Array.isArray(array[i])) { + throw new RangeError('Dimension mismatch ' + + '(' + (size.length + 1) + ' > ' + size.length + ')'); + } + } + } +} + +/** + * Validate whether each element in a multi dimensional array has + * a size corresponding to the provided size array. + * @param {Array} array Array to be validated + * @param {Number[]} size Array with the size of each dimension + * @throws RangeError + */ +exports.validate = function validate(array, size) { + var isScalar = (size.length == 0); + if (isScalar) { + // scalar + if (Array.isArray(array)) { + throw new RangeError('Dimension mismatch (' + array.length + ' != 0)'); + } + } + else { + // array + _validate(array, size, 0); + } +}; + +/** + * Test whether index is an integer number with index >= 0 and index < length + * @param {*} index Zero-based index + * @param {Number} [length] Length of the array + */ +exports.validateIndex = function validateIndex (index, length) { + if (!number.isNumber(index) || !number.isInteger(index)) { + throw new TypeError('Index must be an integer (value: ' + index + ')'); + } + if (index < 0) { + throw new RangeError('Index out of range (' + index + ' < 0)'); + } + if (length !== undefined && index >= length) { + throw new RangeError('Index out of range (' + index + ' >= ' + length + ')'); + } +}; + +/** + * Recursively resize a multi dimensional array + * @param {Array} array Array to be resized + * @param {Number[]} size Array with the size of each dimension + * @param {Number} dim Current dimension + * @param {*} [defaultValue] Value to be filled in in new entries, + * 0 by default. + * @private + */ +function _resize (array, size, dim, defaultValue) { + if (!Array.isArray(array)) { + throw new TypeError('Array expected'); + } + + var len = array.length, + newLen = size[dim]; + + if (len != newLen) { + if(newLen > array.length) { + // enlarge + for (var i = array.length; i < newLen; i++) { + array[i] = defaultValue ? object.clone(defaultValue) : 0; + } + } + else { + // shrink + array.length = size[dim]; + } + len = array.length; + } + + if (dim < size.length - 1) { + // recursively validate each child array + var dimNext = dim + 1; + for (i = 0; i < len; i++) { + child = array[i]; + if (!Array.isArray(child)) { + child = [child]; + array[i] = child; + } + _resize(child, size, dimNext, defaultValue); + } + } + else { + // last dimension + for (i = 0; i < len; i++) { + var child = array[i]; + while (Array.isArray(child)) { + child = child[0]; + } + array[i] = child; + } + } +} + +/** + * Resize a multi dimensional array + * @param {Array} array Array to be resized + * @param {Array.} size Array with the size of each dimension + * @param {*} [defaultValue] Value to be filled in in new entries, + * 0 by default + */ +exports.resize = function resize(array, size, defaultValue) { + // TODO: what to do with scalars, when size=[] ? + + // check the type of size + if (!Array.isArray(size)) { + throw new TypeError('Size must be an array (size is ' + types.type(size) + ')'); + } + + // check whether size contains positive integers + size.forEach(function (value) { + if (!number.isNumber(value) || !number.isInteger(value) || value < 0) { + throw new TypeError('Invalid size, must contain positive integers ' + + '(size: ' + string.format(size) + ')'); + } + }); + + /* TODO: cleanup + var hasZeros = (size.indexOf(0) != -1); + if (hasZeros) { + // array where all dimensions are zero + size.forEach(function (value) { + if (value != 0) { + throw new RangeError('Invalid size, all dimensions must be ' + + 'either zero or non-zero (size: ' + string.format(size) + ')'); + } + }); + } + */ + + // recursively resize + _resize(array, size, 0, defaultValue); +}; + +/** + * Test whether an object is an array + * @param {*} value + * @return {Boolean} isArray + */ +exports.isArray = Array.isArray; \ No newline at end of file diff --git a/lib/util/boolean.js b/lib/util/boolean.js new file mode 100644 index 000000000..dab950308 --- /dev/null +++ b/lib/util/boolean.js @@ -0,0 +1,8 @@ +/** + * Test whether value is a Boolean + * @param {*} value + * @return {Boolean} isBoolean + */ +exports.isBoolean = function isBoolean(value) { + return (value instanceof Boolean) || (typeof value == 'boolean'); +}; diff --git a/lib/util/error.js b/lib/util/error.js new file mode 100644 index 000000000..f30a3f77c --- /dev/null +++ b/lib/util/error.js @@ -0,0 +1,47 @@ +var types = require('./types.js'); + +/** + * Create a TypeError with message: + * 'Function does not support a parameter of type '; + * @param {String} name Function name + * @param {*} value1 + * @param {*} [value2] + * @extends TypeError + */ +exports.UnsupportedTypeError = function UnsupportedTypeError(name, value1, value2) { + if (arguments.length == 2) { + var t = types.type(value1); + this.message = 'Function ' + name + '(' + t + ') not supported'; + } + else if (arguments.length > 2) { + var args = []; + for (var i = 1; i < arguments.length; i++) { + args.push(types.type(arguments[i])); + } + this.message = 'Function ' + name + '(' + args.join(', ') + ') not supported'; + } + else { + this.message = 'Unsupported parameter in function ' + name; + } +}; + +exports.UnsupportedTypeError.prototype = new TypeError(); +exports.UnsupportedTypeError.prototype.name = 'UnsupportedTypeError'; + +/** + * Create a syntax error with the message: + * 'Wrong number of arguments in function ( provided, - expected)' + * @param {String} name Function name + * @param {Number} count Actual argument count + * @param {Number} min Minimum required argument count + * @param {Number} [max] Maximum required argument count + * @extends SyntaxError + */ +exports.ArgumentsError = function ArgumentsError(name, count, min, max) { + this.message = 'Wrong number of arguments in function ' + name + + ' (' + count + ' provided, ' + + min + ((max != undefined) ? ('-' + max) : '') + ' expected)'; +}; + +exports.ArgumentsError.prototype = new SyntaxError(); +exports.ArgumentsError.prototype.name = 'ArgumentError'; diff --git a/lib/util/index.js b/lib/util/index.js new file mode 100644 index 000000000..ea420bdda --- /dev/null +++ b/lib/util/index.js @@ -0,0 +1,7 @@ +exports.array = require('./array'); +exports.boolean = require('./boolean'); +exports.error = require('./error'); +exports.number = require('./number'); +exports.object = require('./object'); +exports.string = require('./string'); +exports.types = require('./types'); diff --git a/lib/util/number.js b/lib/util/number.js new file mode 100644 index 000000000..578aa1213 --- /dev/null +++ b/lib/util/number.js @@ -0,0 +1,87 @@ +var options = require('../options.js'); + +/** + * Test whether value is a Number + * @param {*} value + * @return {Boolean} isNumber + */ +exports.isNumber = function isNumber(value) { + return (value instanceof Number) || (typeof value == 'number'); +}; + +/** + * Check if a number is integer + * @param {Number} value + * @return {Boolean} isInteger + */ +exports.isInteger = function isInteger(value) { + return (value == Math.round(value)); +}; + +/** + * Convert a number to a formatted string representation. + * @param {Number} value The value to be formatted + * @param {Number} [precision] number of digits in formatted output + * @return {String} formattedValue The formatted value + */ +exports.format = function format(value, precision) { + if (value === Infinity) { + return 'Infinity'; + } + else if (value === -Infinity) { + return '-Infinity'; + } + else if (isNaN(value)) { + return 'NaN'; + } + + // TODO: what is a nice limit for non-scientific values? + var abs = Math.abs(value); + if ( (abs > 0.001 && abs < 100000) || abs == 0.0 ) { + // round the value to a limited number of precision + return exports.toPrecision(value, precision); + } + else { + // scientific notation + var exp = Math.round(Math.log(abs) / Math.LN10); + var v = value / (Math.pow(10.0, exp)); + return exports.toPrecision(v, precision) + 'e' + exp; + } +}; + +/** + * Calculate the sign of a number + * @param {Number} x + * @returns {*} + */ +exports.sign = function sign (x) { + if (x > 0) { + return 1; + } + else if (x < 0) { + return -1; + } + else { + return 0; + } +}; + +/** + * Round a value to a maximum number of precision. Trailing zeros will be + * removed. + * @param {Number} value + * @param {Number} [precision] Number of digits in formatted output + * @returns {string} str + */ +exports.toPrecision = function toPrecision (value, precision) { + if (precision === undefined) { + precision = options.precision; + } + + return value.toPrecision(precision).replace(_trailingZeros, function (a, b, c) { + return a.substring(0, a.length - (b.length ? 0 : 1) - c.length); + }); +}; + +/** @private */ +var _trailingZeros = /\.(\d*?)(0+)$/g; diff --git a/lib/util/object.js b/lib/util/object.js new file mode 100644 index 000000000..c5d4b0faf --- /dev/null +++ b/lib/util/object.js @@ -0,0 +1,131 @@ +var number = require('./number.js'), + string = require('./string.js'), + bool = require('./boolean.js'); + +/** + * Clone an object + * + * clone(x) + * + * @param {*} x + * @return {*} clone + */ +exports.clone = function clone(x) { + if (x == null) { + // null or undefined + return x; + } + + if (typeof(x.clone) === 'function') { + return x.clone(); + } + + if (number.isNumber(x) || string.isString(x) || bool.isBoolean(x)) { + return x; + } + + if (Array.isArray(x)) { + return x.map(function (value) { + return clone(value); + }); + } + + if (x instanceof Object) { + var m = {}; + for (var key in x) { + if (x.hasOwnProperty(key)) { + m[key] = clone(x[key]); + } + } + } + + throw new TypeError('Cannot clone ' + x); +}; + +/** + * Extend object a with the properties of object b + * @param {Object} a + * @param {Object} b + * @return {Object} a + */ +exports.extend = function extend (a, b) { + for (var prop in b) { + if (b.hasOwnProperty(prop)) { + a[prop] = b[prop]; + } + } + return a; +}; + +/** + * Deep extend an object a with the properties of object b + * @param {Object} a + * @param {Object} b + * @returns {Object} + */ +exports.deepExtend = function deepExtend (a, b) { + for (var prop in b) { + if (b.hasOwnProperty(prop)) { + if (b[prop] && b[prop].constructor === Object) { + if (a[prop] === undefined) { + a[prop] = {}; + } + if (a[prop].constructor === Object) { + deepExtend(a[prop], b[prop]); + } + else { + a[prop] = b[prop]; + } + } else { + a[prop] = b[prop]; + } + } + } + return a; +}; + +/** + * Deep test equality of all fields in two pairs of arrays or objects. + * @param {Array | Object} a + * @param {Array | Object} b + * @returns {boolean} + */ +exports.deepEqual = function deepEqual (a, b) { + var prop, i, len; + if (Array.isArray(a)) { + if (!Array.isArray(b)) { + return false; + } + + for (i = 0, len = a.length; i < len; i++) { + if (!exports.deepEqual(a[i], b[i])) { + return false; + } + } + return true; + } + else if (a instanceof Object) { + if (Array.isArray(b) || !(b instanceof Object)) { + return false; + } + + for (prop in a) { + if (a.hasOwnProperty(prop)) { + if (!exports.deepEqual(a[prop], b[prop])) { + return false; + } + } + } + for (prop in b) { + if (b.hasOwnProperty(prop)) { + if (!exports.deepEqual(a[prop], b[prop])) { + return false; + } + } + } + return true; + } + else { + return (a.valueOf() == b.valueOf()); + } +}; diff --git a/lib/util/string.js b/lib/util/string.js new file mode 100644 index 000000000..072e70241 --- /dev/null +++ b/lib/util/string.js @@ -0,0 +1,150 @@ +var number = require('./number.js'); + +/** + * Test whether value is a String + * @param {*} value + * @return {Boolean} isString + */ +exports.isString = function isString(value) { + return (value instanceof String) || (typeof value == 'string'); +}; + +/** + * Check if a text ends with a certain string. + * @param {String} text + * @param {String} search + */ +exports.endsWith = function endsWith(text, search) { + var start = text.length - search.length; + var end = text.length; + return (text.substring(start, end) === search); +}; + +/** + * Format a value of any type into a string. Interpolate values into the string. + * Numbers are rounded off to a maximum number of 5 digits by default. + * Usage: + * math.format(value) + * math.format(template, object) + * + * Example usage: + * math.format(2/7); // '0.28571' + * math.format(new Complex(2, 3)); // '2 + 3i' + * math.format('Hello $name! The date is $date', { + * name: 'user', + * date: new Date().toISOString().substring(0, 10) + * }); // 'hello user! The date is 2013-03-23' + * + * @param {String | *} template Template or value + * @param {Object} [values] + * @return {String} str + */ +exports.format = function format(template, values) { + var num = arguments.length; + + if (num == 1) { + // just format a value as string + var value = arguments[0]; + if (number.isNumber(value)) { + return number.format(value); + } + + if (Array.isArray(value)) { + return formatArray(value); + } + + if (exports.isString(value)) { + return '"' + value + '"'; + } + + if (value instanceof Object) { + return value.toString(); + } + + return String(value); + } + else { + if (!exports.isString(template)) { + throw new TypeError('String expected as first parameter in function format'); + } + if (!(values instanceof Object)) { + throw new TypeError('Object expected as second parameter in function format'); + } + + // format values into a string + return template.replace(/\$([\w\.]+)/g, function (original, key) { + var keys = key.split('.'); + var value = values[keys.shift()]; + while (keys.length && value != undefined) { + var k = keys.shift(); + value = k ? value[k] : value + '.'; + } + return value != undefined ? value : original; + } + ); + } +}; + +/** + * Recursively format an n-dimensional matrix + * Example output: "[[1, 2], [3, 4]]" + * @param {Array} array + * @returns {String} str + */ +function formatArray (array) { + if (Array.isArray(array)) { + var str = '['; + var len = array.length; + for (var i = 0; i < len; i++) { + if (i != 0) { + str += ', '; + } + str += formatArray(array[i]); + } + str += ']'; + return str; + } + else { + return exports.format(array); + } +} + +/** + * Recursively format an n-dimensional array, output looks like + * "[1, 2, 3]" + * @param {Array} array + * @returns {string} str + */ +/* TODO: use function formatArray2d or remove it +function formatArray2d (array) { + var str = '['; + var s = size(array); + + if (s.length != 2) { + throw new RangeError('Array must be two dimensional (size: ' + + formatArray(s) + ')'); + } + + var rows = s[0]; + var cols = s[1]; + for (var r = 0; r < rows; r++) { + if (r != 0) { + str += '; '; + } + + var row = array[r]; + for (var c = 0; c < cols; c++) { + if (c != 0) { + str += ', '; + } + var cell = row[c]; + if (cell != undefined) { + str += exports.format(cell); + } + } + } + str += ']'; + + return str; +} +*/ \ No newline at end of file diff --git a/lib/util/types.js b/lib/util/types.js new file mode 100644 index 000000000..7b3d39fcb --- /dev/null +++ b/lib/util/types.js @@ -0,0 +1,66 @@ +/** + * Determine the type of a variable + * + * typeof(x) + * + * @param {*} x + * @return {String} type Lower case type, for example "number", "string", + * "array". + */ +exports.type = function type (x) { + var type = typeof x, + name; + + if (type == 'object') { + if (x == null) { + return 'null'; + } + if (x instanceof Boolean) { + return 'boolean'; + } + if (x instanceof Number) { + return 'number'; + } + if (x instanceof String) { + return 'string'; + } + if (Array.isArray(x)) { + return 'array'; + } + if (x instanceof Date) { + return 'date'; + } + if (x.constructor) { + // search data types + for (name in types) { + if (types.hasOwnProperty(name)) { + if (x.constructor == types[name]) { + return name.toLowerCase(); + } + } + } + + // try the constructors name as last resort + if (x.constructor.name) { + return x.constructor.name.toLowerCase(); + } + } + } + + return type; +}; + +/** + * Custom registered types, for example {'matrix': Matrix} + * @private + */ +var types = {}; + +/** + * Register a new type, for example addType('matrix', Matrix) + * @param {String} name Lower case name of the type + * @param {Function} type Prototype function of the type + */ +exports.addType = function addType (name, type) { + types[name] = type; +}; From a6b4ad7526665659af776d502ba2a95169f0f5a1 Mon Sep 17 00:00:00 2001 From: Sebastien Piquemal Date: Wed, 14 Aug 2013 15:43:32 +0400 Subject: [PATCH 3/4] fixed tests --- test/contstants.test.js | 2 +- test/expr/parser.test.js | 2 +- test/expr/scope.test.js | 2 +- test/function/arithmetic/abs.test.js | 2 +- test/function/arithmetic/add.test.js | 2 +- test/function/arithmetic/ceil.test.js | 2 +- test/function/arithmetic/cube.test.js | 2 +- test/function/arithmetic/divide.test.js | 2 +- test/function/arithmetic/edivide.test.js | 2 +- test/function/arithmetic/emultiply.test.js | 2 +- test/function/arithmetic/epow.test.js | 2 +- test/function/arithmetic/equal.test.js | 2 +- test/function/arithmetic/exp.test.js | 2 +- test/function/arithmetic/fix.test.js | 2 +- test/function/arithmetic/floor.test.js | 2 +- test/function/arithmetic/gcd.test.js | 2 +- test/function/arithmetic/larger.test.js | 2 +- test/function/arithmetic/largereq.test.js | 2 +- test/function/arithmetic/lcm.test.js | 2 +- test/function/arithmetic/log.test.js | 2 +- test/function/arithmetic/log10.test.js | 2 +- test/function/arithmetic/mod.test.js | 2 +- test/function/arithmetic/multiply.test.js | 2 +- test/function/arithmetic/pow.test.js | 2 +- test/function/arithmetic/round.test.js | 2 +- test/function/arithmetic/sign.test.js | 2 +- test/function/arithmetic/smaller.test.js | 2 +- test/function/arithmetic/smallereq.test.js | 2 +- test/function/arithmetic/sqrt.test.js | 2 +- test/function/arithmetic/square.test.js | 2 +- test/function/arithmetic/subtract.test.js | 2 +- test/function/arithmetic/unary.js | 2 +- test/function/arithmetic/unequal.test.js | 2 +- test/function/arithmetic/xgcd.test.js | 2 +- test/function/complex/arg.test.js | 2 +- test/function/complex/conj.test.js | 2 +- test/function/complex/im.test.js | 2 +- test/function/complex/re.test.js | 2 +- test/function/construction/boolean.test.js | 2 +- test/function/construction/complex.test.js | 2 +- test/function/construction/matrix.test.js | 2 +- test/function/construction/number.test.js | 2 +- test/function/construction/range.test.js | 2 +- test/function/construction/string.test.js | 2 +- test/function/construction/unit.test.js | 2 +- test/function/example.test.js | 2 +- test/function/matrix/concat.test.js | 2 +- test/function/matrix/det.test.js | 2 +- test/function/matrix/diag.test.js | 2 +- test/function/matrix/eye.test.js | 2 +- test/function/matrix/inv.test.js | 2 +- test/function/matrix/ones.test.js | 2 +- test/function/matrix/size.test.js | 2 +- test/function/matrix/squeeze.test.js | 2 +- test/function/matrix/subset.test.js | 2 +- test/function/matrix/transpose.test.js | 2 +- test/function/matrix/zeros.test.js | 2 +- test/function/probability/factorial.test.js | 2 +- test/function/probability/random.test.js | 2 +- test/function/statistics/max.test.js | 2 +- test/function/statistics/min.test.js | 2 +- test/function/trigonometry/acos.test.js | 2 +- test/function/trigonometry/asin.test.js | 2 +- test/function/trigonometry/atan.test.js | 2 +- test/function/trigonometry/atan2.test.js | 2 +- test/function/trigonometry/cos.test.js | 2 +- test/function/trigonometry/cot.test.js | 2 +- test/function/trigonometry/csc.test.js | 2 +- test/function/trigonometry/sec.test.js | 2 +- test/function/trigonometry/sin.test.js | 2 +- test/function/trigonometry/tan.test.js | 2 +- test/function/units/in.test.js | 2 +- test/function/utils/clone.test.js | 2 +- test/function/utils/eval.test.js | 2 +- test/function/utils/format.test.js | 2 +- test/function/utils/help.test.js | 2 +- test/function/utils/import.test.js | 2 +- test/function/utils/parse.test.js | 2 +- test/function/utils/select.test.js | 2 +- test/function/utils/typeof.test.js | 2 +- test/type/complex.test.js | 2 +- test/type/help.test.js | 2 +- test/type/matrix.test.js | 2 +- test/type/range.test.js | 2 +- test/type/unit.test.js | 2 +- 85 files changed, 85 insertions(+), 85 deletions(-) diff --git a/test/contstants.test.js b/test/contstants.test.js index 8c142d845..11ebc06f3 100644 --- a/test/contstants.test.js +++ b/test/contstants.test.js @@ -1,5 +1,5 @@ var assert = require('assert'), - math = require('../lib/index.js'), + math = require('../index.js'), approx = require('../tools/approx.js'); // pi diff --git a/test/expr/parser.test.js b/test/expr/parser.test.js index 0269c02da..557d7bae8 100644 --- a/test/expr/parser.test.js +++ b/test/expr/parser.test.js @@ -2,7 +2,7 @@ var assert = require('assert'), approx = require('../../tools/approx.js'), - math = require('../../lib/index.js'), + math = require('../../index.js'), matrix = math.matrix, range = math.range, round = math.round; diff --git a/test/expr/scope.test.js b/test/expr/scope.test.js index 7b954f3fb..395af71a9 100644 --- a/test/expr/scope.test.js +++ b/test/expr/scope.test.js @@ -1,7 +1,7 @@ // test Scope var assert = require('assert'), approx = require('../../tools/approx.js'), - math = require('../../lib/index.js'), + math = require('../../index.js'), Scope = math.expr.Scope; describe('Scope', function() { diff --git a/test/function/arithmetic/abs.test.js b/test/function/arithmetic/abs.test.js index 54d7f956d..2d539ff80 100644 --- a/test/function/arithmetic/abs.test.js +++ b/test/function/arithmetic/abs.test.js @@ -1,6 +1,6 @@ // test abs var assert = require('assert'); -var math = require('../../../lib/index.js'); +var math = require('../../../index.js'); describe('abs', function () { diff --git a/test/function/arithmetic/add.test.js b/test/function/arithmetic/add.test.js index 016c3e08d..28241b252 100644 --- a/test/function/arithmetic/add.test.js +++ b/test/function/arithmetic/add.test.js @@ -1,6 +1,6 @@ // test add var assert = require('assert'); -var math = require('../../../lib/index.js'); +var math = require('../../../index.js'); describe('add', function() { diff --git a/test/function/arithmetic/ceil.test.js b/test/function/arithmetic/ceil.test.js index a8da29f51..1fa943f24 100644 --- a/test/function/arithmetic/ceil.test.js +++ b/test/function/arithmetic/ceil.test.js @@ -1,7 +1,7 @@ // test ceil var assert = require('assert'), approx = require('../../../tools/approx.js'), - math = require('../../../lib/index.js'), + math = require('../../../index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/arithmetic/cube.test.js b/test/function/arithmetic/cube.test.js index 4a6fd2441..ad15bca46 100644 --- a/test/function/arithmetic/cube.test.js +++ b/test/function/arithmetic/cube.test.js @@ -1,6 +1,6 @@ // test cube var assert = require('assert'), - math = require('../../../lib/index.js'), + math = require('../../../index.js'), unit = math.unit, matrix = math.matrix, range = math.range, diff --git a/test/function/arithmetic/divide.test.js b/test/function/arithmetic/divide.test.js index b9315fe03..edd95ad70 100644 --- a/test/function/arithmetic/divide.test.js +++ b/test/function/arithmetic/divide.test.js @@ -1,6 +1,6 @@ // test divide var assert = require('assert'); -math = require('../../../lib/index.js'), +math = require('../../../index.js'), approx = require('../../../tools/approx.js'), divide = math.divide, complex = math.complex; diff --git a/test/function/arithmetic/edivide.test.js b/test/function/arithmetic/edivide.test.js index dd37641e7..7f053235e 100644 --- a/test/function/arithmetic/edivide.test.js +++ b/test/function/arithmetic/edivide.test.js @@ -1,6 +1,6 @@ // test edivide (element-wise divide) var assert = require('assert'); -math = require('../../../lib/index.js'), +math = require('../../../index.js'), approx = require('../../../tools/approx.js'), edivide = math.edivide, complex = math.complex; diff --git a/test/function/arithmetic/emultiply.test.js b/test/function/arithmetic/emultiply.test.js index e49cd0d34..be5416c15 100644 --- a/test/function/arithmetic/emultiply.test.js +++ b/test/function/arithmetic/emultiply.test.js @@ -1,6 +1,6 @@ // test emultiply (element-wise multiply) var assert = require('assert'), - math = require('../../../lib/index.js'), + math = require('../../../index.js'), approx = require('../../../tools/approx.js'), emultiply = math.emultiply, divide = math.divide, diff --git a/test/function/arithmetic/epow.test.js b/test/function/arithmetic/epow.test.js index afa850c0b..c693999eb 100644 --- a/test/function/arithmetic/epow.test.js +++ b/test/function/arithmetic/epow.test.js @@ -1,7 +1,7 @@ // test exp var assert = require('assert'), approx = require('../../../tools/approx.js'), - math = require('../../../lib/index.js'), + math = require('../../../index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/arithmetic/equal.test.js b/test/function/arithmetic/equal.test.js index cf3ae9333..2b2ead1e9 100644 --- a/test/function/arithmetic/equal.test.js +++ b/test/function/arithmetic/equal.test.js @@ -1,6 +1,6 @@ // test equal var assert = require('assert'), - math = require('../../../lib/index.js'), + math = require('../../../index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/arithmetic/exp.test.js b/test/function/arithmetic/exp.test.js index 80946ea4a..3803ba101 100644 --- a/test/function/arithmetic/exp.test.js +++ b/test/function/arithmetic/exp.test.js @@ -1,7 +1,7 @@ // test exp var assert = require('assert'), approx = require('../../../tools/approx.js'), - math = require('../../../lib/index.js'), + math = require('../../../index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/arithmetic/fix.test.js b/test/function/arithmetic/fix.test.js index 0f8c4b6aa..270311f55 100644 --- a/test/function/arithmetic/fix.test.js +++ b/test/function/arithmetic/fix.test.js @@ -1,7 +1,7 @@ // test fix var assert = require('assert'), approx = require('../../../tools/approx.js'), - math = require('../../../lib/index.js'), + math = require('../../../index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/arithmetic/floor.test.js b/test/function/arithmetic/floor.test.js index 8f2c23f44..fa4b2456e 100644 --- a/test/function/arithmetic/floor.test.js +++ b/test/function/arithmetic/floor.test.js @@ -1,7 +1,7 @@ // test floor var assert = require('assert'), approx = require('../../../tools/approx.js'), - math = require('../../../lib/index.js'), + math = require('../../../index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/arithmetic/gcd.test.js b/test/function/arithmetic/gcd.test.js index 53a135da3..0c8d3254e 100644 --- a/test/function/arithmetic/gcd.test.js +++ b/test/function/arithmetic/gcd.test.js @@ -1,6 +1,6 @@ // test gcd var assert = require('assert'); -var math = require('../../../lib/index.js'); +var math = require('../../../index.js'); describe('gcd', function() { diff --git a/test/function/arithmetic/larger.test.js b/test/function/arithmetic/larger.test.js index f84589e5c..db555751f 100644 --- a/test/function/arithmetic/larger.test.js +++ b/test/function/arithmetic/larger.test.js @@ -1,6 +1,6 @@ // test larger var assert = require('assert'), - math = require('../../../lib/index.js'), + math = require('../../../index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/arithmetic/largereq.test.js b/test/function/arithmetic/largereq.test.js index e14399a2a..50df2fd0f 100644 --- a/test/function/arithmetic/largereq.test.js +++ b/test/function/arithmetic/largereq.test.js @@ -1,6 +1,6 @@ // test largereq var assert = require('assert'), - math = require('../../../lib/index.js'), + math = require('../../../index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/arithmetic/lcm.test.js b/test/function/arithmetic/lcm.test.js index 2373b5456..ed47a85d4 100644 --- a/test/function/arithmetic/lcm.test.js +++ b/test/function/arithmetic/lcm.test.js @@ -1,5 +1,5 @@ var assert = require('assert'); -var math = require('../../../lib/index.js'); +var math = require('../../../index.js'); describe('lcm', function() { diff --git a/test/function/arithmetic/log.test.js b/test/function/arithmetic/log.test.js index 46b19e788..e94c70f0e 100644 --- a/test/function/arithmetic/log.test.js +++ b/test/function/arithmetic/log.test.js @@ -1,7 +1,7 @@ // test exp var assert = require('assert'), approx = require('../../../tools/approx.js'), - math = require('../../../lib/index.js'), + math = require('../../../index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/arithmetic/log10.test.js b/test/function/arithmetic/log10.test.js index f03747b67..6486e783e 100644 --- a/test/function/arithmetic/log10.test.js +++ b/test/function/arithmetic/log10.test.js @@ -1,7 +1,7 @@ // test exp var assert = require('assert'), approx = require('../../../tools/approx.js'), - math = require('../../../lib/index.js'), + math = require('../../../index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/arithmetic/mod.test.js b/test/function/arithmetic/mod.test.js index 412142e8a..bb96460ae 100644 --- a/test/function/arithmetic/mod.test.js +++ b/test/function/arithmetic/mod.test.js @@ -1,7 +1,7 @@ // test mod var assert = require('assert'), approx = require('../../../tools/approx.js'), - math = require('../../../lib/index.js'), + math = require('../../../index.js'), matrix = math.matrix, range = math.range, mod = math.mod; diff --git a/test/function/arithmetic/multiply.test.js b/test/function/arithmetic/multiply.test.js index 931fc1f11..3be1b0306 100644 --- a/test/function/arithmetic/multiply.test.js +++ b/test/function/arithmetic/multiply.test.js @@ -1,6 +1,6 @@ // test multiply var assert = require('assert'), - math = require('../../../lib/index.js'), + math = require('../../../index.js'), approx = require('../../../tools/approx.js'), multiply = math.multiply, divide = math.divide, diff --git a/test/function/arithmetic/pow.test.js b/test/function/arithmetic/pow.test.js index 15feae36b..2b9df0f7f 100644 --- a/test/function/arithmetic/pow.test.js +++ b/test/function/arithmetic/pow.test.js @@ -1,7 +1,7 @@ // test exp var assert = require('assert'), approx = require('../../../tools/approx.js'), - math = require('../../../lib/index.js'), + math = require('../../../index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/arithmetic/round.test.js b/test/function/arithmetic/round.test.js index d6578886e..ccfb78725 100644 --- a/test/function/arithmetic/round.test.js +++ b/test/function/arithmetic/round.test.js @@ -1,6 +1,6 @@ // test round var assert = require('assert'); -var math = require('../../../lib/index.js'); +var math = require('../../../index.js'); describe('round', function() { diff --git a/test/function/arithmetic/sign.test.js b/test/function/arithmetic/sign.test.js index 1380019a7..ea9fde895 100644 --- a/test/function/arithmetic/sign.test.js +++ b/test/function/arithmetic/sign.test.js @@ -1,6 +1,6 @@ // test sign var assert = require('assert'); -var math = require('../../../lib/index.js'); +var math = require('../../../index.js'); describe('sign', function() { diff --git a/test/function/arithmetic/smaller.test.js b/test/function/arithmetic/smaller.test.js index c9b2d90f4..842c68568 100644 --- a/test/function/arithmetic/smaller.test.js +++ b/test/function/arithmetic/smaller.test.js @@ -1,6 +1,6 @@ // test smaller var assert = require('assert'), - math = require('../../../lib/index.js'), + math = require('../../../index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/arithmetic/smallereq.test.js b/test/function/arithmetic/smallereq.test.js index c6ecc0196..a7f73ae2b 100644 --- a/test/function/arithmetic/smallereq.test.js +++ b/test/function/arithmetic/smallereq.test.js @@ -1,6 +1,6 @@ // test smaller var assert = require('assert'), - math = require('../../../lib/index.js'), + math = require('../../../index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/arithmetic/sqrt.test.js b/test/function/arithmetic/sqrt.test.js index 6ecc69fc1..3c10bbe96 100644 --- a/test/function/arithmetic/sqrt.test.js +++ b/test/function/arithmetic/sqrt.test.js @@ -1,7 +1,7 @@ // test sqrt var assert = require('assert'), approx = require('../../../tools/approx.js'), - math = require('../../../lib/index.js'); + math = require('../../../index.js'); describe('sqrt', function() { diff --git a/test/function/arithmetic/square.test.js b/test/function/arithmetic/square.test.js index 1f226c76b..9d511b422 100644 --- a/test/function/arithmetic/square.test.js +++ b/test/function/arithmetic/square.test.js @@ -1,6 +1,6 @@ // test square var assert = require('assert'), - math = require('../../../lib/index.js'), + math = require('../../../index.js'), unit = math.unit, matrix = math.matrix, range = math.range, diff --git a/test/function/arithmetic/subtract.test.js b/test/function/arithmetic/subtract.test.js index c28ce61f7..8f7925715 100644 --- a/test/function/arithmetic/subtract.test.js +++ b/test/function/arithmetic/subtract.test.js @@ -1,6 +1,6 @@ // test subtract var assert = require('assert'); -var math = require('../../../lib/index.js'); +var math = require('../../../index.js'); describe('subtract', function() { diff --git a/test/function/arithmetic/unary.js b/test/function/arithmetic/unary.js index 6b3ea094c..f2b219bd7 100644 --- a/test/function/arithmetic/unary.js +++ b/test/function/arithmetic/unary.js @@ -1,6 +1,6 @@ // test unary minus var assert = require('assert'); -var math = require('../../../lib/index.js'); +var math = require('../../../index.js'); describe('unaryminus', function() { diff --git a/test/function/arithmetic/unequal.test.js b/test/function/arithmetic/unequal.test.js index 9067f3b48..1b44f9db5 100644 --- a/test/function/arithmetic/unequal.test.js +++ b/test/function/arithmetic/unequal.test.js @@ -1,6 +1,6 @@ // test equal var assert = require('assert'), - math = require('../../../lib/index.js'), + math = require('../../../index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/arithmetic/xgcd.test.js b/test/function/arithmetic/xgcd.test.js index fb5dbdc68..f7e5d2fa8 100644 --- a/test/function/arithmetic/xgcd.test.js +++ b/test/function/arithmetic/xgcd.test.js @@ -1,6 +1,6 @@ // test xgcd var assert = require('assert'); -var math = require('../../../lib/index.js'); +var math = require('../../../index.js'); describe('xgcd', function() { diff --git a/test/function/complex/arg.test.js b/test/function/complex/arg.test.js index 3fb5898b2..8d58b7e77 100644 --- a/test/function/complex/arg.test.js +++ b/test/function/complex/arg.test.js @@ -1,5 +1,5 @@ var assert = require('assert'); -var math = require('../../../lib/index.js'); +var math = require('../../../index.js'); describe('arg', function() { diff --git a/test/function/complex/conj.test.js b/test/function/complex/conj.test.js index 6f25903ec..4c2d3f4fa 100644 --- a/test/function/complex/conj.test.js +++ b/test/function/complex/conj.test.js @@ -1,5 +1,5 @@ var assert = require('assert'); -var math = require('../../../lib/index.js'); +var math = require('../../../index.js'); describe('conj', function() { diff --git a/test/function/complex/im.test.js b/test/function/complex/im.test.js index bd05bd885..814232eb2 100644 --- a/test/function/complex/im.test.js +++ b/test/function/complex/im.test.js @@ -1,5 +1,5 @@ var assert = require('assert'); -var math = require('../../../lib/index.js'); +var math = require('../../../index.js'); describe('im', function() { diff --git a/test/function/complex/re.test.js b/test/function/complex/re.test.js index b5b9d612b..5ac263a1d 100644 --- a/test/function/complex/re.test.js +++ b/test/function/complex/re.test.js @@ -1,5 +1,5 @@ var assert = require('assert'); -var math = require('../../../lib/index.js'); +var math = require('../../../index.js'); describe('re', function() { diff --git a/test/function/construction/boolean.test.js b/test/function/construction/boolean.test.js index ac5c83403..981c08fb6 100644 --- a/test/function/construction/boolean.test.js +++ b/test/function/construction/boolean.test.js @@ -1,5 +1,5 @@ var assert = require('assert'), - math = require('../../../lib/index.js'), + math = require('../../../index.js'), bool = math.boolean; describe('boolean', function() { diff --git a/test/function/construction/complex.test.js b/test/function/construction/complex.test.js index b35a2dd4e..5dbcea3dc 100644 --- a/test/function/construction/complex.test.js +++ b/test/function/construction/complex.test.js @@ -1,5 +1,5 @@ var assert = require('assert'), - math = require('../../../lib/index.js'), + math = require('../../../index.js'), complex = math.complex; describe('complex', function() { diff --git a/test/function/construction/matrix.test.js b/test/function/construction/matrix.test.js index f3a952ac2..d8c0581a9 100644 --- a/test/function/construction/matrix.test.js +++ b/test/function/construction/matrix.test.js @@ -1,6 +1,6 @@ // test matrix construction var assert = require('assert'), - math = require('../../../lib/index.js'), + math = require('../../../index.js'), matrix = math.matrix; describe('matrix', function() { diff --git a/test/function/construction/number.test.js b/test/function/construction/number.test.js index c71d609e0..0e95e0c2d 100644 --- a/test/function/construction/number.test.js +++ b/test/function/construction/number.test.js @@ -1,5 +1,5 @@ var assert = require('assert'), - math = require('../../../lib/index.js'), + math = require('../../../index.js'), approx = require('../../../tools/approx.js'), number = math.number; diff --git a/test/function/construction/range.test.js b/test/function/construction/range.test.js index 9afae046f..e95194957 100644 --- a/test/function/construction/range.test.js +++ b/test/function/construction/range.test.js @@ -1,5 +1,5 @@ var assert = require('assert'), - math = require('../../../lib/index.js'), + math = require('../../../index.js'), range = math.range; describe('range', function() { diff --git a/test/function/construction/string.test.js b/test/function/construction/string.test.js index 21ea30c7e..1a10e89da 100644 --- a/test/function/construction/string.test.js +++ b/test/function/construction/string.test.js @@ -1,5 +1,5 @@ var assert = require('assert'), - math = require('../../../lib/index.js'), + math = require('../../../index.js'), string = math.string; describe('string', function() { diff --git a/test/function/construction/unit.test.js b/test/function/construction/unit.test.js index 8649f5063..3bdde2183 100644 --- a/test/function/construction/unit.test.js +++ b/test/function/construction/unit.test.js @@ -1,5 +1,5 @@ var assert = require('assert'), - math = require('../../../lib/index.js'), + math = require('../../../index.js'), unit = math.unit; describe('unit', function() { diff --git a/test/function/example.test.js b/test/function/example.test.js index 8b7887bb6..a3dd692b7 100644 --- a/test/function/example.test.js +++ b/test/function/example.test.js @@ -3,7 +3,7 @@ return; var assert = require('assert'), approx = require('../../tools/approx.js'), - math = require('../../lib/index.js'), + math = require('../../index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/matrix/concat.test.js b/test/function/matrix/concat.test.js index 3e387abb3..1c77780c8 100644 --- a/test/function/matrix/concat.test.js +++ b/test/function/matrix/concat.test.js @@ -1,6 +1,6 @@ // test concat var assert = require('assert'); -var math = require('../../../lib/index.js'); +var math = require('../../../index.js'); assert.deepEqual(math.concat([1,2,3], [4]), [1,2,3,4]); assert.deepEqual(math.concat([[1],[2],[3]], [[4]], 0), [[1],[2],[3],[4]]); diff --git a/test/function/matrix/det.test.js b/test/function/matrix/det.test.js index 9a7163a7b..043eb9462 100644 --- a/test/function/matrix/det.test.js +++ b/test/function/matrix/det.test.js @@ -1,6 +1,6 @@ // test det var assert = require('assert'); -var math = require('../../../lib/index.js'); +var math = require('../../../index.js'); assert.equal(math.det(3), 3); assert.equal(math.det([5]), 5); diff --git a/test/function/matrix/diag.test.js b/test/function/matrix/diag.test.js index 037680de9..7c4850b8a 100644 --- a/test/function/matrix/diag.test.js +++ b/test/function/matrix/diag.test.js @@ -1,5 +1,5 @@ var assert = require('assert'); -var math = require('../../../lib/index.js'); +var math = require('../../../index.js'); // test diag assert.deepEqual(math.diag([1,2,3]).valueOf(), [[1,0,0],[0,2,0],[0,0,3]]); diff --git a/test/function/matrix/eye.test.js b/test/function/matrix/eye.test.js index ba2aaeb73..b6856715a 100644 --- a/test/function/matrix/eye.test.js +++ b/test/function/matrix/eye.test.js @@ -1,6 +1,6 @@ // test eye var assert = require('assert'); -var math = require('../../../lib/index.js'); +var math = require('../../../index.js'); assert.deepEqual(math.eye().valueOf(), [[1]]); assert.deepEqual(math.eye([]).valueOf(), [[1]]); diff --git a/test/function/matrix/inv.test.js b/test/function/matrix/inv.test.js index 0359da3c5..9b9ca3585 100644 --- a/test/function/matrix/inv.test.js +++ b/test/function/matrix/inv.test.js @@ -1,6 +1,6 @@ // test inv var assert = require('assert'); -var math = require('../../../lib/index.js'); +var math = require('../../../index.js'); assert.deepEqual(math.inv(4), 1/4); assert.deepEqual(math.inv([4]), [1/4]); diff --git a/test/function/matrix/ones.test.js b/test/function/matrix/ones.test.js index 726c95671..8fa304b7d 100644 --- a/test/function/matrix/ones.test.js +++ b/test/function/matrix/ones.test.js @@ -1,6 +1,6 @@ // test ones var assert = require('assert'); -var math = require('../../../lib/index.js'), +var math = require('../../../index.js'), ones = math.ones; describe('ones', function() { diff --git a/test/function/matrix/size.test.js b/test/function/matrix/size.test.js index d1ab84d2b..3e4da8189 100644 --- a/test/function/matrix/size.test.js +++ b/test/function/matrix/size.test.js @@ -1,6 +1,6 @@ // test size var assert = require('assert'); -var math = require('../../../lib/index.js'); +var math = require('../../../index.js'); describe('size', function() { diff --git a/test/function/matrix/squeeze.test.js b/test/function/matrix/squeeze.test.js index 8e8a04a6a..621833f33 100644 --- a/test/function/matrix/squeeze.test.js +++ b/test/function/matrix/squeeze.test.js @@ -1,6 +1,6 @@ // test squeeze var assert = require('assert'); -var math = require('../../../lib/index.js'), +var math = require('../../../index.js'), squeeze = math.squeeze, size = math.size, matrix = math.matrix; diff --git a/test/function/matrix/subset.test.js b/test/function/matrix/subset.test.js index b329d8fd5..a55286501 100644 --- a/test/function/matrix/subset.test.js +++ b/test/function/matrix/subset.test.js @@ -1,6 +1,6 @@ // test subset var assert = require('assert'), - math = require('../../../lib/index.js'), + math = require('../../../index.js'), subset = math.subset, matrix = math.matrix, range = math.range; diff --git a/test/function/matrix/transpose.test.js b/test/function/matrix/transpose.test.js index f4e85d3ed..f220484d5 100644 --- a/test/function/matrix/transpose.test.js +++ b/test/function/matrix/transpose.test.js @@ -1,6 +1,6 @@ // test transpose var assert = require('assert'); -var math = require('../../../lib/index.js'); +var math = require('../../../index.js'); describe('transpose', function() { diff --git a/test/function/matrix/zeros.test.js b/test/function/matrix/zeros.test.js index f608b322d..194282ffd 100644 --- a/test/function/matrix/zeros.test.js +++ b/test/function/matrix/zeros.test.js @@ -1,6 +1,6 @@ // test zeros var assert = require('assert'); -var math = require('../../../lib/index.js'), +var math = require('../../../index.js'), zeros = math.zeros; describe('zeros', function() { diff --git a/test/function/probability/factorial.test.js b/test/function/probability/factorial.test.js index 52db77fa1..e81ce368b 100644 --- a/test/function/probability/factorial.test.js +++ b/test/function/probability/factorial.test.js @@ -1,6 +1,6 @@ // test factorial var assert = require('assert'); -var math = require('../../../lib/index.js'); +var math = require('../../../index.js'); assert.equal(math.factorial(0), 1); assert.equal(math.factorial(1), 1); diff --git a/test/function/probability/random.test.js b/test/function/probability/random.test.js index 470a9d3a0..1eb9d328f 100644 --- a/test/function/probability/random.test.js +++ b/test/function/probability/random.test.js @@ -1,6 +1,6 @@ var assert = require('assert'), _ = require('underscore'), - math = require('../../../lib/index.js'); + math = require('../../../index.js'); var assertApproxEqual = function(testVal, val, tolerance) { var diff = Math.abs(val - testVal); diff --git a/test/function/statistics/max.test.js b/test/function/statistics/max.test.js index 904914fb3..1e7fe5280 100644 --- a/test/function/statistics/max.test.js +++ b/test/function/statistics/max.test.js @@ -1,6 +1,6 @@ // test max var assert = require('assert'); -var math = require('../../../lib/index.js'); +var math = require('../../../index.js'); assert.equal(math.max(5), 5); assert.equal(math.max(3,1), 3); diff --git a/test/function/statistics/min.test.js b/test/function/statistics/min.test.js index 733a9c547..0c65e0a1e 100644 --- a/test/function/statistics/min.test.js +++ b/test/function/statistics/min.test.js @@ -1,6 +1,6 @@ // test min var assert = require('assert'); -var math = require('../../../lib/index.js'); +var math = require('../../../index.js'); assert.equal(math.min(5), 5); assert.equal(math.min(1,3), 1); diff --git a/test/function/trigonometry/acos.test.js b/test/function/trigonometry/acos.test.js index e96809256..2cbf2e9ec 100644 --- a/test/function/trigonometry/acos.test.js +++ b/test/function/trigonometry/acos.test.js @@ -1,6 +1,6 @@ // test acos var assert = require('assert'), - math = require('../../../lib/index.js'), + math = require('../../../index.js'), approx = require('../../../tools/approx.js'), pi = math.pi, acos = math.acos, diff --git a/test/function/trigonometry/asin.test.js b/test/function/trigonometry/asin.test.js index f3c41198a..a1bebae99 100644 --- a/test/function/trigonometry/asin.test.js +++ b/test/function/trigonometry/asin.test.js @@ -1,6 +1,6 @@ // test asin var assert = require('assert'), - math = require('../../../lib/index.js'), + math = require('../../../index.js'), approx = require('../../../tools/approx.js'), pi = math.pi, complex = math.complex, diff --git a/test/function/trigonometry/atan.test.js b/test/function/trigonometry/atan.test.js index 966b04783..d3289fc03 100644 --- a/test/function/trigonometry/atan.test.js +++ b/test/function/trigonometry/atan.test.js @@ -1,6 +1,6 @@ // test atan var assert = require('assert'), - math = require('../../../lib/index.js'), + math = require('../../../index.js'), approx = require('../../../tools/approx.js'), pi = math.pi, complex = math.complex, diff --git a/test/function/trigonometry/atan2.test.js b/test/function/trigonometry/atan2.test.js index af8b353e2..bcf0f5f94 100644 --- a/test/function/trigonometry/atan2.test.js +++ b/test/function/trigonometry/atan2.test.js @@ -1,6 +1,6 @@ // test atan2 var assert = require('assert'), - math = require('../../../lib/index.js'), + math = require('../../../index.js'), approx = require('../../../tools/approx.js'), pi = math.pi, acos = math.acos, diff --git a/test/function/trigonometry/cos.test.js b/test/function/trigonometry/cos.test.js index 7aa30aefe..0a118684d 100644 --- a/test/function/trigonometry/cos.test.js +++ b/test/function/trigonometry/cos.test.js @@ -1,6 +1,6 @@ // test cos var assert = require('assert'), - math = require('../../../lib/index.js'), + math = require('../../../index.js'), approx = require('../../../tools/approx.js'), pi = math.pi, complex = math.complex, diff --git a/test/function/trigonometry/cot.test.js b/test/function/trigonometry/cot.test.js index ed747b533..5b67072bf 100644 --- a/test/function/trigonometry/cot.test.js +++ b/test/function/trigonometry/cot.test.js @@ -1,6 +1,6 @@ // test cot var assert = require('assert'), - math = require('../../../lib/index.js'), + math = require('../../../index.js'), approx = require('../../../tools/approx.js'), pi = math.pi, complex = math.complex, diff --git a/test/function/trigonometry/csc.test.js b/test/function/trigonometry/csc.test.js index f21505d7a..7b6dfeddb 100644 --- a/test/function/trigonometry/csc.test.js +++ b/test/function/trigonometry/csc.test.js @@ -1,6 +1,6 @@ // test csc var assert = require('assert'), - math = require('../../../lib/index.js'), + math = require('../../../index.js'), approx = require('../../../tools/approx.js'), pi = math.pi, complex = math.complex, diff --git a/test/function/trigonometry/sec.test.js b/test/function/trigonometry/sec.test.js index 87bb15662..1aa0a2b90 100644 --- a/test/function/trigonometry/sec.test.js +++ b/test/function/trigonometry/sec.test.js @@ -1,6 +1,6 @@ // test sec var assert = require('assert'), - math = require('../../../lib/index.js'), + math = require('../../../index.js'), approx = require('../../../tools/approx.js'), pi = math.pi, complex = math.complex, diff --git a/test/function/trigonometry/sin.test.js b/test/function/trigonometry/sin.test.js index 8e58ca2ae..ed32edd2f 100644 --- a/test/function/trigonometry/sin.test.js +++ b/test/function/trigonometry/sin.test.js @@ -1,6 +1,6 @@ // test sin var assert = require('assert'), - math = require('../../../lib/index.js'), + math = require('../../../index.js'), approx = require('../../../tools/approx.js'), pi = math.pi, complex = math.complex, diff --git a/test/function/trigonometry/tan.test.js b/test/function/trigonometry/tan.test.js index aaa042bb1..9a9f9e781 100644 --- a/test/function/trigonometry/tan.test.js +++ b/test/function/trigonometry/tan.test.js @@ -1,6 +1,6 @@ // test tan var assert = require('assert'), - math = require('../../../lib/index.js'), + math = require('../../../index.js'), approx = require('../../../tools/approx.js'), pi = math.pi, complex = math.complex, diff --git a/test/function/units/in.test.js b/test/function/units/in.test.js index 398480fbc..b7fd2cd93 100644 --- a/test/function/units/in.test.js +++ b/test/function/units/in.test.js @@ -2,7 +2,7 @@ var assert = require('assert'), approx = require('../../../tools/approx.js'), - math = require('../../../lib/index.js'), + math = require('../../../index.js'), unit = math.unit; // test function in diff --git a/test/function/utils/clone.test.js b/test/function/utils/clone.test.js index a23c0b1a9..bca72d591 100644 --- a/test/function/utils/clone.test.js +++ b/test/function/utils/clone.test.js @@ -1,6 +1,6 @@ // test clone var assert = require('assert'); -var math = require('../../../lib/index.js'); +var math = require('../../../index.js'); var a = 1; var b = math.clone(a); diff --git a/test/function/utils/eval.test.js b/test/function/utils/eval.test.js index 2270d2196..8a758258b 100644 --- a/test/function/utils/eval.test.js +++ b/test/function/utils/eval.test.js @@ -1,6 +1,6 @@ // test eval var assert = require('assert'); -var math = require('../../../lib/index.js'); +var math = require('../../../index.js'); // test some expressions assert.equal(math.eval('pi'), Math.PI); diff --git a/test/function/utils/format.test.js b/test/function/utils/format.test.js index 15abedd73..a06755a89 100644 --- a/test/function/utils/format.test.js +++ b/test/function/utils/format.test.js @@ -1,6 +1,6 @@ // test format var assert = require('assert'); -var math = require('../../../lib/index.js'); +var math = require('../../../index.js'); assert.equal(math.format(2/7), '0.28571'); assert.equal(math.format(0.10400), '0.104'); diff --git a/test/function/utils/help.test.js b/test/function/utils/help.test.js index 5c695a106..7f332c130 100644 --- a/test/function/utils/help.test.js +++ b/test/function/utils/help.test.js @@ -1,6 +1,6 @@ // test help var assert = require('assert'); -var math = require('../../../lib/index.js'); +var math = require('../../../index.js'); var prop; var help = math.help('sin'); diff --git a/test/function/utils/import.test.js b/test/function/utils/import.test.js index 3ff61a1dc..cfffc1611 100644 --- a/test/function/utils/import.test.js +++ b/test/function/utils/import.test.js @@ -1,6 +1,6 @@ // test import var assert = require('assert'), - math = require('../../../lib/index.js'), + math = require('../../../index.js'), approx = require('../../../tools/approx.js'); math.import({ diff --git a/test/function/utils/parse.test.js b/test/function/utils/parse.test.js index 65b3ea962..f42cf30a6 100644 --- a/test/function/utils/parse.test.js +++ b/test/function/utils/parse.test.js @@ -1,6 +1,6 @@ // test parse var assert = require('assert'); -var math = require('../../../lib/index.js'); +var math = require('../../../index.js'); // test some expressions assert.ok(math.parse('pi') instanceof math.expr.node.Node); diff --git a/test/function/utils/select.test.js b/test/function/utils/select.test.js index 96c66c9c0..39494c497 100644 --- a/test/function/utils/select.test.js +++ b/test/function/utils/select.test.js @@ -1,7 +1,7 @@ // test select (chaining of operations) var assert = require('assert'), approx = require('../../../tools/approx.js'), - math = require('../../../lib/index.js'); + math = require('../../../index.js'); assert.ok(math.select(45) instanceof math.expr.Selector); assert.equal(math.select(3).add(4).subtract(2).done(), 5); diff --git a/test/function/utils/typeof.test.js b/test/function/utils/typeof.test.js index f4204ef9f..4eb38591f 100644 --- a/test/function/utils/typeof.test.js +++ b/test/function/utils/typeof.test.js @@ -1,6 +1,6 @@ // test typeof var assert = require('assert'); -var math = require('../../../lib/index.js'); +var math = require('../../../index.js'); assert.equal(math.typeof(2), 'number'); assert.equal(math.typeof(new Number(2)), 'number'); diff --git a/test/type/complex.test.js b/test/type/complex.test.js index 3775e35c5..d59ad92ad 100644 --- a/test/type/complex.test.js +++ b/test/type/complex.test.js @@ -1,7 +1,7 @@ // test data type Complex var assert = require('assert'); -var math = require('../../lib/index.js'); +var math = require('../../index.js'); describe('Complex', function () { diff --git a/test/type/help.test.js b/test/type/help.test.js index b36b1584e..e8b45985d 100644 --- a/test/type/help.test.js +++ b/test/type/help.test.js @@ -1,6 +1,6 @@ // test Help var assert = require('assert'); -var math = require('../../lib/index.js'); +var math = require('../../index.js'); var help = new math.type.Help(math, math.docs.sin); diff --git a/test/type/matrix.test.js b/test/type/matrix.test.js index 33fd58966..184c1d608 100644 --- a/test/type/matrix.test.js +++ b/test/type/matrix.test.js @@ -1,7 +1,7 @@ // test data type Matrix var assert = require('assert'); -var math = require('../../lib/index.js'); +var math = require('../../index.js'); var m = math.matrix(); assert.equal(m.isScalar(), true); diff --git a/test/type/range.test.js b/test/type/range.test.js index dee1c23b7..5e877faac 100644 --- a/test/type/range.test.js +++ b/test/type/range.test.js @@ -1,7 +1,7 @@ // test data type Range var assert = require('assert'); -var math = require('../../lib/index.js'); +var math = require('../../index.js'); var r = math.range(2,6); assert.deepEqual(r.toArray(), [2,3,4,5]); diff --git a/test/type/unit.test.js b/test/type/unit.test.js index 0ccc1d9c1..1b0a78bc3 100644 --- a/test/type/unit.test.js +++ b/test/type/unit.test.js @@ -1,7 +1,7 @@ // test data type Unit var assert = require('assert'); -var math = require('../../lib/index.js'); +var math = require('../../index.js'); var unit1 = math.unit(5000, 'cm'); From 1c85b5f7ed0919a79dde57ec11ce435f3e62899d Mon Sep 17 00:00:00 2001 From: Sebastien Piquemal Date: Wed, 14 Aug 2013 15:54:24 +0400 Subject: [PATCH 4/4] fixed examples --- examples/basic_usage.js | 2 +- examples/chained_operations.js | 2 +- examples/complex_numbers.js | 2 +- examples/expressions.js | 2 +- examples/import.js | 2 +- examples/matrices.js | 2 +- examples/units.js | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/basic_usage.js b/examples/basic_usage.js index 1530fc169..092a24f5b 100644 --- a/examples/basic_usage.js +++ b/examples/basic_usage.js @@ -1,7 +1,7 @@ // basic usage // load math.js -var math = require('../dist/math.js'); +var math = require('../index'); /** * Helper function to output a value in the console. Value will be formatted. diff --git a/examples/chained_operations.js b/examples/chained_operations.js index 6cf07822f..21b876438 100644 --- a/examples/chained_operations.js +++ b/examples/chained_operations.js @@ -1,7 +1,7 @@ // chained operations // load math.js -var math = require('../dist/math.js'); +var math = require('../index'); /** * Helper function to output a value in the console. Value will be formatted. diff --git a/examples/complex_numbers.js b/examples/complex_numbers.js index 93551504c..8818add21 100644 --- a/examples/complex_numbers.js +++ b/examples/complex_numbers.js @@ -1,7 +1,7 @@ // complex numbers // load math.js -var math = require('../dist/math.js'); +var math = require('../index'); /** * Helper function to output a value in the console. Value will be formatted. diff --git a/examples/expressions.js b/examples/expressions.js index fec48c021..795ed09ed 100644 --- a/examples/expressions.js +++ b/examples/expressions.js @@ -8,7 +8,7 @@ */ // load math.js -var math = require('../dist/math.js'); +var math = require('../index'); /** * Helper function to output a value in the console. Value will be formatted. diff --git a/examples/import.js b/examples/import.js index 1f72c7d2d..85314fdaf 100644 --- a/examples/import.js +++ b/examples/import.js @@ -4,7 +4,7 @@ * with functions and variables. */ -var math = require('../dist/math.js'); +var math = require('../index'); /** * Helper function to output a value in the console. Value will be formatted. diff --git a/examples/matrices.js b/examples/matrices.js index 1ccb288d0..6503424cf 100644 --- a/examples/matrices.js +++ b/examples/matrices.js @@ -1,7 +1,7 @@ // matrices // load math.js -var math = require('../dist/math.js'); +var math = require('../index'); /** * Helper function to output a value in the console. Value will be formatted. diff --git a/examples/units.js b/examples/units.js index 91e93b040..17e5ca36a 100644 --- a/examples/units.js +++ b/examples/units.js @@ -1,7 +1,7 @@ // units // load math.js -var math = require('../dist/math.js'); +var math = require('../index'); /** * Helper function to output a value in the console. Value will be formatted.