← Back to team overview

ubuntu-touch-coreapps-reviewers team mailing list archive

[Merge] lp:~gang65/ubuntu-calculator-app/reboot-upgrade-math-js-to-1.5 into lp:ubuntu-calculator-app/reboot

 

Bartosz Kosiorek has proposed merging lp:~gang65/ubuntu-calculator-app/reboot-upgrade-math-js-to-1.5 into lp:ubuntu-calculator-app/reboot.

Commit message:
Upgrade math.js to 1.5.0

Requested reviews:
  Ubuntu Calculator Developers (ubuntu-calculator-dev)
Related bugs:
  Bug #1439846 in Ubuntu Calculator App: "Upgrade math.js to 1.5.0"
  https://bugs.launchpad.net/ubuntu-calculator-app/+bug/1439846

For more details, see:
https://code.launchpad.net/~gang65/ubuntu-calculator-app/reboot-upgrade-math-js-to-1.5/+merge/255315

Upgrade math.js to 1.5.0
-- 
Your team Ubuntu Calculator Developers is requested to review the proposed merge of lp:~gang65/ubuntu-calculator-app/reboot-upgrade-math-js-to-1.5 into lp:ubuntu-calculator-app/reboot.
=== modified file 'app/engine/math.js'
--- app/engine/math.js	2015-03-02 09:15:57 +0000
+++ app/engine/math.js	2015-04-07 00:03:58 +0000
@@ -14,11 +14,11 @@
  * It features real and complex numbers, units, matrices, a large set of
  * mathematical functions, and a flexible expression parser.
  *
- * @version 1.2.0
- * @date    2014-12-25
+ * @version 1.5.0
+ * @date    2015-03-28
  *
  * @license
- * Copyright (C) 2013-2014 Jos de Jong <wjosdejong@xxxxxxxxx>
+ * Copyright (C) 2013-2015 Jos de Jong <wjosdejong@xxxxxxxxx>
  *
  * 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
@@ -40,41 +40,41 @@
 return /******/ (function(modules) { // webpackBootstrap
 /******/ 	// The module cache
 /******/ 	var installedModules = {};
-/******/
+
 /******/ 	// The require function
 /******/ 	function __webpack_require__(moduleId) {
-/******/
+
 /******/ 		// Check if module is in cache
 /******/ 		if(installedModules[moduleId])
 /******/ 			return installedModules[moduleId].exports;
-/******/
+
 /******/ 		// Create a new module (and put it into the cache)
 /******/ 		var module = installedModules[moduleId] = {
 /******/ 			exports: {},
 /******/ 			id: moduleId,
 /******/ 			loaded: false
 /******/ 		};
-/******/
+
 /******/ 		// Execute the module function
 /******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
-/******/
+
 /******/ 		// Flag the module as loaded
 /******/ 		module.loaded = true;
-/******/
+
 /******/ 		// Return the exports of the module
 /******/ 		return module.exports;
 /******/ 	}
-/******/
-/******/
+
+
 /******/ 	// expose the modules object (__webpack_modules__)
 /******/ 	__webpack_require__.m = modules;
-/******/
+
 /******/ 	// expose the module cache
 /******/ 	__webpack_require__.c = installedModules;
-/******/
+
 /******/ 	// __webpack_public_path__
 /******/ 	__webpack_require__.p = "";
-/******/
+
 /******/ 	// Load entry module and return exports
 /******/ 	return __webpack_require__(0);
 /******/ })
@@ -162,27 +162,27 @@
 
 	      // TODO: remove deprecated setting some day (deprecated since version 0.17.0)
 	      if (options.number && options.number.defaultType) {
-	        throw new Error('setting `number.defaultType` is deprecated. Use `number` instead.')
+	        throw new Error('setting `number.defaultType` is deprecated. Use `number` instead.');
 	      }
 
 	      // TODO: remove deprecated setting some day (deprecated since version 0.17.0)
 	      if (options.number && options.number.precision) {
-	        throw new Error('setting `number.precision` is deprecated. Use `precision` instead.')
+	        throw new Error('setting `number.precision` is deprecated. Use `precision` instead.');
 	      }
 
 	      // TODO: remove deprecated setting some day (deprecated since version 0.17.0)
 	      if (options.matrix && options.matrix.defaultType) {
-	        throw new Error('setting `matrix.defaultType` is deprecated. Use `matrix` instead.')
+	        throw new Error('setting `matrix.defaultType` is deprecated. Use `matrix` instead.');
 	      }
 
 	      // TODO: remove deprecated setting some day (deprecated since version 0.15.0)
 	      if (options.matrix && options.matrix['default']) {
-	        throw new Error('setting `matrix.default` is deprecated. Use `matrix` instead.')
+	        throw new Error('setting `matrix.default` is deprecated. Use `matrix` instead.');
 	      }
 
 	      // TODO: remove deprecated setting some day (deprecated since version 0.20.0)
 	      if (options.decimals) {
-	        throw new Error('setting `decimals` is deprecated. Use `precision` instead.')
+	        throw new Error('setting `decimals` is deprecated. Use `precision` instead.');
 	      }
 	    }
 
@@ -207,6 +207,29 @@
 	  // create a new BigNumber factory for this instance of math.js
 	  var BigNumber = __webpack_require__(5).constructor();
 
+	  /**
+	   * Get a JSON representation of a BigNumber containing
+	   * type information
+	   * @returns {Object} Returns a JSON object structured as:
+	   *                   `{"mathjs": "BigNumber", "value": "0.2"}`
+	   */
+	  BigNumber.prototype.toJSON = function () {
+	    return {
+	      mathjs: 'BigNumber',
+	      value: this.toString()
+	    };
+	  };
+
+	  /**
+	   * Instantiate a BigNumber from a JSON object
+	   * @param {Object} json  a JSON object structured as:
+	   *                       `{"mathjs": "BigNumber", "value": "0.2"}`
+	   * @return {BigNumber}
+	   */
+	  BigNumber.fromJSON = function (json) {
+	    return new BigNumber(json.value);
+	  };
+
 	  // extend BigNumber with a function clone
 	  if (typeof BigNumber.prototype.clone !== 'function') {
 	    /**
@@ -248,33 +271,39 @@
 	  math.type.Complex = __webpack_require__(7);
 	  math.type.Range = __webpack_require__(8);
 	  math.type.Index = __webpack_require__(9);
-	  math.type.Matrix = __webpack_require__(10);
+	  math.type.Matrix = __webpack_require__(10)(_config);
 	  math.type.Unit = __webpack_require__(11);
 	  math.type.Help = __webpack_require__(12);
 	  math.type.ResultSet = __webpack_require__(13);
 	  math.type.BigNumber = BigNumber;
 
-	  math.collection = __webpack_require__(14);
+	  math.collection = __webpack_require__(14)(math, _config);
+
+	  // matrix storage formats
+	  math.type.CcsMatrix = __webpack_require__(15)(math, _config);
+	  math.type.CrsMatrix = __webpack_require__(16)(math, _config);
+	  math.type.DenseMatrix = __webpack_require__(17)(math, _config);
+
+	  // matrix storage format registry
+	  math.type.Matrix._storage.ccs = math.type.CcsMatrix;
+	  math.type.Matrix._storage.crs = math.type.CrsMatrix;
+	  math.type.Matrix._storage.dense = math.type.DenseMatrix;
+	  math.type.Matrix._storage['default'] = math.type.DenseMatrix;
 
 	  // expression (parse, Parser, nodes, docs)
 	  math.expression = {};
-	  math.expression.node = __webpack_require__(15);
-	  math.expression.parse = __webpack_require__(16);
-	  math.expression.Parser = __webpack_require__(17);
-	  math.expression.docs = __webpack_require__(18);
+	  math.expression.node = __webpack_require__(18);
+	  math.expression.parse = __webpack_require__(19)(math, _config);
+	  math.expression.Parser = __webpack_require__(20)(math, _config);
+	  math.expression.docs = __webpack_require__(21);
 
 	  // serialization utilities
 	  math.json = {
-	    reviver: __webpack_require__(19)
+	    reviver: __webpack_require__(22)(math, _config)
 	  };
-
-	  // expression parser
-	  __webpack_require__(31)(math, _config);
-	  __webpack_require__(32)(math, _config);
-	  __webpack_require__(33)(math, _config);
+	  
+	  // functions - construction (must be defined before the rest of functions)
 	  __webpack_require__(34)(math, _config);
-
-	  // functions - arithmetic
 	  __webpack_require__(35)(math, _config);
 	  __webpack_require__(36)(math, _config);
 	  __webpack_require__(37)(math, _config);
@@ -284,10 +313,14 @@
 	  __webpack_require__(41)(math, _config);
 	  __webpack_require__(42)(math, _config);
 	  __webpack_require__(43)(math, _config);
+
+	  // expression parser
 	  __webpack_require__(44)(math, _config);
 	  __webpack_require__(45)(math, _config);
 	  __webpack_require__(46)(math, _config);
 	  __webpack_require__(47)(math, _config);
+
+	  // functions - arithmetic
 	  __webpack_require__(48)(math, _config);
 	  __webpack_require__(49)(math, _config);
 	  __webpack_require__(50)(math, _config);
@@ -304,8 +337,6 @@
 	  __webpack_require__(61)(math, _config);
 	  __webpack_require__(62)(math, _config);
 	  __webpack_require__(63)(math, _config);
-
-	  // functions - bitwise
 	  __webpack_require__(64)(math, _config);
 	  __webpack_require__(65)(math, _config);
 	  __webpack_require__(66)(math, _config);
@@ -313,16 +344,14 @@
 	  __webpack_require__(68)(math, _config);
 	  __webpack_require__(69)(math, _config);
 	  __webpack_require__(70)(math, _config);
-
-	  // functions - complex
 	  __webpack_require__(71)(math, _config);
 	  __webpack_require__(72)(math, _config);
 	  __webpack_require__(73)(math, _config);
 	  __webpack_require__(74)(math, _config);
-
-	  // functions - construction
 	  __webpack_require__(75)(math, _config);
 	  __webpack_require__(76)(math, _config);
+
+	  // functions - bitwise
 	  __webpack_require__(77)(math, _config);
 	  __webpack_require__(78)(math, _config);
 	  __webpack_require__(79)(math, _config);
@@ -330,18 +359,20 @@
 	  __webpack_require__(81)(math, _config);
 	  __webpack_require__(82)(math, _config);
 	  __webpack_require__(83)(math, _config);
+
+	  // functions - complex
 	  __webpack_require__(84)(math, _config);
-
-	  // functions - logical
 	  __webpack_require__(85)(math, _config);
 	  __webpack_require__(86)(math, _config);
 	  __webpack_require__(87)(math, _config);
+
+	  // functions - logical
 	  __webpack_require__(88)(math, _config);
-
-	  // functions - matrix
 	  __webpack_require__(89)(math, _config);
 	  __webpack_require__(90)(math, _config);
 	  __webpack_require__(91)(math, _config);
+
+	  // functions - matrix
 	  __webpack_require__(92)(math, _config);
 	  __webpack_require__(93)(math, _config);
 	  __webpack_require__(94)(math, _config);
@@ -356,41 +387,41 @@
 	  __webpack_require__(103)(math, _config);
 	  __webpack_require__(104)(math, _config);
 	  __webpack_require__(105)(math, _config);
-
-	  // functions - probability
-	  //require('./function/probability/distribution')(math, _config); // TODO: rethink math.distribution
 	  __webpack_require__(106)(math, _config);
 	  __webpack_require__(107)(math, _config);
 	  __webpack_require__(108)(math, _config);
+
+	  // functions - probability
+	  //require('./function/probability/distribution')(math, _config); // TODO: rethink math.distribution
 	  __webpack_require__(109)(math, _config);
 	  __webpack_require__(110)(math, _config);
 	  __webpack_require__(111)(math, _config);
 	  __webpack_require__(112)(math, _config);
-
-	  // functions - relational
 	  __webpack_require__(113)(math, _config);
 	  __webpack_require__(114)(math, _config);
 	  __webpack_require__(115)(math, _config);
+
+	  // functions - relational
 	  __webpack_require__(116)(math, _config);
 	  __webpack_require__(117)(math, _config);
 	  __webpack_require__(118)(math, _config);
 	  __webpack_require__(119)(math, _config);
 	  __webpack_require__(120)(math, _config);
-
-	  // functions - statistics
 	  __webpack_require__(121)(math, _config);
 	  __webpack_require__(122)(math, _config);
 	  __webpack_require__(123)(math, _config);
+
+	  // functions - statistics
 	  __webpack_require__(124)(math, _config);
 	  __webpack_require__(125)(math, _config);
 	  __webpack_require__(126)(math, _config);
 	  __webpack_require__(127)(math, _config);
 	  __webpack_require__(128)(math, _config);
-
-	  // functions - trigonometry
 	  __webpack_require__(129)(math, _config);
 	  __webpack_require__(130)(math, _config);
 	  __webpack_require__(131)(math, _config);
+
+	  // functions - trigonometry
 	  __webpack_require__(132)(math, _config);
 	  __webpack_require__(133)(math, _config);
 	  __webpack_require__(134)(math, _config);
@@ -413,20 +444,23 @@
 	  __webpack_require__(151)(math, _config);
 	  __webpack_require__(152)(math, _config);
 	  __webpack_require__(153)(math, _config);
-
-	  // functions - units
 	  __webpack_require__(154)(math, _config);
-
-	  // functions - utils
 	  __webpack_require__(155)(math, _config);
 	  __webpack_require__(156)(math, _config);
+
+	  // functions - units
 	  __webpack_require__(157)(math, _config);
+
+	  // functions - utils
 	  __webpack_require__(158)(math, _config);
 	  __webpack_require__(159)(math, _config);
 	  __webpack_require__(160)(math, _config);
 	  __webpack_require__(161)(math, _config);
 	  __webpack_require__(162)(math, _config);
 	  __webpack_require__(163)(math, _config);
+	  __webpack_require__(164)(math, _config);
+	  __webpack_require__(165)(math, _config);
+	  __webpack_require__(166)(math, _config);
 
 	  // TODO: deprecated since version 0.25.0, remove some day.
 	  math.ifElse = function () {
@@ -438,21 +472,21 @@
 
 	  // attach transform functions (for converting one-based indices to zero-based)
 	  math.expression.transform = {
-	    concat: __webpack_require__(20)(math, _config),
-	    filter: __webpack_require__(21)(math, _config),
-	    forEach:__webpack_require__(22)(math, _config),
-	    index:  __webpack_require__(23)(math, _config),
-	    map:    __webpack_require__(24)(math, _config),
-	    max:    __webpack_require__(25)(math, _config),
-	    mean:   __webpack_require__(26)(math, _config),
-	    min:    __webpack_require__(27)(math, _config),
-	    range:  __webpack_require__(28)(math, _config),
-	    subset: __webpack_require__(29)(math, _config)
+	    concat: __webpack_require__(23)(math, _config),
+	    filter: __webpack_require__(24)(math, _config),
+	    forEach:__webpack_require__(25)(math, _config),
+	    index:  __webpack_require__(26)(math, _config),
+	    map:    __webpack_require__(27)(math, _config),
+	    max:    __webpack_require__(28)(math, _config),
+	    mean:   __webpack_require__(29)(math, _config),
+	    min:    __webpack_require__(30)(math, _config),
+	    range:  __webpack_require__(31)(math, _config),
+	    subset: __webpack_require__(32)(math, _config)
 	  };
 
 	  // selector (we initialize after all functions are loaded)
 	  math.chaining = {};
-	  math.chaining.Chain = __webpack_require__(30)(math, _config);
+	  math.chaining.Chain = __webpack_require__(33)(math, _config);
 	  math.chaining.Selector = math.chaining.Chain; // TODO: deprecate in v2.0
 
 	  // apply provided configuration options
@@ -829,44 +863,15 @@
 	      return exports.toExponential(value, precision);
 
 	    case 'auto':
-	      // determine lower and upper bound for exponential notation.
-	        // TODO: implement support for upper and lower to be BigNumbers themselves
-	      var lower = 1e-3;
-	      var upper = 1e5;
-	      if (options && options.exponential) {
-	        if (options.exponential.lower !== undefined) {
-	          lower = options.exponential.lower;
-	        }
-	        if (options.exponential.upper !== undefined) {
-	          upper = options.exponential.upper;
-	        }
-	      }
-
-	      // handle special case zero
-	      if (value === 0) return '0';
-
-	      // determine whether or not to output exponential notation
-	      var str;
-	      var abs = Math.abs(value);
-	      if (abs >= lower && abs < upper) {
-	        // normal number notation
-	        // Note: IE7 does not allow value.toPrecision(undefined)
-	        var valueStr = precision ?
-	            value.toPrecision(Math.min(precision, 21)) :
-	            value.toPrecision();
-	        str = parseFloat(valueStr) + '';
-	      }
-	      else {
-	        // exponential notation
-	        str = exports.toExponential(value, precision);
-	      }
-
-	      // remove trailing zeros after the decimal point
-	      return str.replace(/((\.\d*?)(0+))($|e)/, function () {
-	        var digits = arguments[2];
-	        var e = arguments[4];
-	        return (digits !== '.') ? digits + e : e;
-	      });
+	      return exports
+	          .toPrecision(value, precision, options && options.exponential)
+
+	          // remove trailing zeros after the decimal point
+	          .replace(/((\.\d*?)(0+))($|e)/, function () {
+	            var digits = arguments[2];
+	            var e = arguments[4];
+	            return (digits !== '.') ? digits + e : e;
+	          });
 
 	    default:
 	      throw new Error('Unknown notation "' + notation + '". ' +
@@ -883,6 +888,7 @@
 	 * @returns {string} str
 	 */
 	exports.toExponential = function(value, precision) {
+	  // Note: IE7 does not allow value.toExponential(undefined)
 	  if (precision !== undefined) {
 	    return value.toExponential(Math.min(precision - 1, 20));
 	  }
@@ -898,8 +904,134 @@
 	 *                                      decimal point. Zero by default.
 	 */
 	exports.toFixed = function(value, precision) {
-	  return value.toFixed(Math.min(precision, 20));
-	};
+	  var abs = Math.abs(value);
+	  if ((abs > 1e-20 && abs < 1e20) || abs === 0) {
+	    return value.toFixed(Math.min(precision, 20));
+	  }
+	  else {
+	    var str = exports.toPrecision(value, undefined, {
+	      lower: -Infinity,
+	      upper: Infinity
+	    });
+
+	    var dot = str.indexOf('.');
+	    var actual = (dot !== -1) ? (str.length - dot - 1) : 0;
+	    var required = precision != undefined ? precision : 0;
+
+	    if (required > actual) {
+	      // append zeros
+	      return str + (dot === -1 ? '.' : '') + repeat('0', required - actual);
+	    }
+	    else if (required < actual) {
+	      // remove decimals
+
+	      var end = dot + (required > 0 ? required + 1 : 0);
+
+	      if (parseInt(str.charAt(end)) < 5) {
+	        // no need to round, just remove the tail
+	        return str.substring(0, end);
+	      }
+	      else {
+	        // round up
+
+	        // move the dot temporarily to the place where we have to round
+	        var tempDot = str.substring(0, dot) +
+	            str.substring(dot + 1, end) + '.' +
+	            str.substring(end);
+
+	        // round to the correct number of digits
+	        var zeros = tempDot.match(/^0*/); // leading zeros
+	        var fixed = (zeros ? zeros[0] : '') + parseFloat(tempDot).toFixed();
+
+	        // restore the original dot
+	        if (required > 0) {
+	          return fixed.substring(0, dot) + '.' + fixed.substring(dot);
+	        }
+	        else {
+	          return fixed.substring(0, dot);
+	        }
+	      }
+	    }
+	    else {
+	      return str;
+	    }
+	  }
+	};
+
+	/**
+	 * Format a number with a certain precision
+	 * @param {Number} value
+	 * @param {Number} [precision=undefined] Optional number of digits.
+	 * @param {{lower: number, upper: number}} [options]  By default:
+	 *                                                    lower = 1e-3 (excl)
+	 *                                                    upper = 1e+5 (incl)
+	 * @return {string}
+	 */
+	exports.toPrecision = function(value, precision, options) {
+	  // determine lower and upper bound for exponential notation.
+	  var lower = (options && options.lower !== undefined) ? options.lower : 1e-3;
+	  var upper = (options && options.upper !== undefined) ? options.upper : 1e+5;
+
+	  // handle special case zero
+	  if (value === 0) return '0';
+
+	  // determine whether or not to output exponential notation
+	  var abs = Math.abs(value);
+	  if (abs < lower || abs >= upper) {
+	    // exponential notation
+	    return exports.toExponential(value, precision);
+	  }
+	  else {
+	    // normal number notation
+
+	    // split coefficient and exponent
+	    var str         = exports.toExponential(value, precision);
+	    var match       = str.match(/^(-?[\d.]+)e([+-]?\d+)$/);
+	    var coefficient = match[1];
+	    var exponent    = parseFloat(match[2]);
+	    var digits      = coefficient.replace('.', '');
+
+	    if (exponent === 0) {
+	      // return as is
+	      return coefficient;
+	    }
+	    else if (exponent > 0) {
+	      var diff = exponent + 1 - digits.length;
+	      if (diff >= 0) {
+	        // append zeros
+	        return digits + repeat('0', diff);
+	      }
+	      else {
+	        // insert the dot at the right place
+	        return digits.substr(0, exponent + 1) + '.' + digits.substr(exponent + 1);
+	      }
+	    }
+	    else { // exponent < 0
+	      return '0.' + repeat('0', -(exponent + 1)) + digits;
+	    }
+	  }
+	};
+
+	/**
+	 * Repeat a string
+	 * http://stackoverflow.com/a/5450113/1262753
+	 * @param {string} pattern
+	 * @param {number} count
+	 * @returns {string}
+	 */
+	function repeat(pattern, count) {
+	  var c = count;
+	  if (c < 1) return '';
+	  var result = '';
+	  while (c > 1) {
+	    if (c & 1) {
+	      result += pattern;
+	    }
+	    c >>= 1;
+	    pattern += pattern;
+	  }
+	  return result + pattern;
+	}
 
 	/**
 	 * Count the number of significant digits of a number.
@@ -970,14 +1102,14 @@
 
 	module.exports = function (math, config) {
 	  var object = __webpack_require__(2);
-	  var bignumber = __webpack_require__(164);
+	  var bignumber = __webpack_require__(167);
 	  var Complex = __webpack_require__(7);
 	  var BigNumber = math.type.BigNumber;
 
 	  math['true']     = true;
 	  math['false']    = false;
 	  math['null']     = null;
-	  math['uninitialized'] = __webpack_require__(165).UNINITIALIZED;
+	  math['uninitialized'] = __webpack_require__(168).UNINITIALIZED;
 
 	  if (config.number === 'bignumber') {
 	    math['Infinity'] = new BigNumber(Infinity);
@@ -1022,7 +1154,7 @@
 	  math.i = new Complex(0, 1);
 
 	  // meta information
-	  math.version = __webpack_require__(166);
+	  math.version = __webpack_require__(169);
 	};
 
 
@@ -1030,33 +1162,10 @@
 /* 5 */
 /***/ function(module, exports, __webpack_require__) {
 
-	var BigNumber = __webpack_require__(336);
+	var BigNumber = __webpack_require__(339);
 
 	// FIXME: replace all require('decimal.js') with require('./BigNumber').
 
-	/**
-	 * Get a JSON representation of a BigNumber containing
-	 * type information
-	 * @returns {Object} Returns a JSON object structured as:
-	 *                   `{"mathjs": "BigNumber", "value": "0.2"}`
-	 */
-	BigNumber.prototype.toJSON = function () {
-	  return {
-	    mathjs: 'BigNumber',
-	    value: this.toString()
-	  };
-	};
-
-	/**
-	 * Instantiate a BigNumber from a JSON object
-	 * @param {Object} json  a JSON object structured as:
-	 *                       `{"mathjs": "BigNumber", "value": "0.2"}`
-	 * @return {BigNumber}
-	 */
-	BigNumber.fromJSON = function (json) {
-	  return new BigNumber(json.value);
-	};
-
 	module.exports = BigNumber;
 
 
@@ -1066,10 +1175,10 @@
 
 	'use strict';
 
-	exports.ArgumentsError = __webpack_require__(167);
-	exports.DimensionError = __webpack_require__(168);
-	exports.IndexError = __webpack_require__(169);
-	exports.UnsupportedTypeError = __webpack_require__(170);
+	exports.ArgumentsError = __webpack_require__(170);
+	exports.DimensionError = __webpack_require__(171);
+	exports.IndexError = __webpack_require__(172);
+	exports.UnsupportedTypeError = __webpack_require__(173);
 
 	// TODO: implement an InvalidValueError?
 
@@ -1080,7 +1189,7 @@
 
 	'use strict';
 
-	var util = __webpack_require__(171),
+	var util = __webpack_require__(174),
 	    Unit = __webpack_require__(11),
 	    number = util.number,
 
@@ -1559,7 +1668,7 @@
 
 	'use strict';
 
-	var util = __webpack_require__(171);
+	var util = __webpack_require__(174);
 
 	var number = util.number;
 	var string = util.string;
@@ -1858,7 +1967,7 @@
 
 	'use strict';
 
-	var util = __webpack_require__(171),
+	var util = __webpack_require__(174),
 
 	    Range = __webpack_require__(8),
 
@@ -2155,542 +2264,268 @@
 
 	'use strict';
 
-	var util = __webpack_require__(171);
-	var DimensionError = __webpack_require__(168);
-
-	var Index = __webpack_require__(9);
-
-	var number = util.number;
-	var string = util.string;
-	var array = util.array;
-	var object = util.object;
-
-	var isArray = Array.isArray;
-	var validateIndex = array.validateIndex;
-
-	/**
-	 * @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 function 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.subset([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('Constructor must be called with the new operator');
-	  }
-
-	  if (data instanceof Matrix) {
-	    // clone data from a Matrix
-	    this._data = data.clone()._data;
-	  }
-	  else if (isArray(data)) {
-	    // use array
-	    // replace nested Matrices with Arrays
-	    this._data = preprocess(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 subset of the matrix, or replace a subset of the matrix.
-	 *
-	 * Usage:
-	 *     var subset = matrix.subset(index)               // retrieve subset
-	 *     var value = matrix.subset(index, replacement)   // replace subset
-	 *
-	 * @param {Index} index
-	 * @param {Array | Matrix | *} [replacement]
-	 * @param {*} [defaultValue=0]      Default value, filled in on new entries when
-	 *                                  the matrix is resized. If not provided,
-	 *                                  new matrix elements will be filled with zeros.
-	 */
-	Matrix.prototype.subset = function (index, replacement, defaultValue) {
-	  switch (arguments.length) {
-	    case 1:
-	      return _get(this, index);
-
-	    // intentional fall through
-	    case 2:
-	    case 3:
-	      return _set(this, index, replacement, defaultValue);
-
-	    default:
-	      throw new SyntaxError('Wrong number of arguments');
-	  }
-	};
-
-	/**
-	 * Get a single element from the matrix.
-	 * @param {Number[]} index   Zero-based index
-	 * @return {*} value
-	 */
-	Matrix.prototype.get = function (index) {
-	  if (!isArray(index)) {
-	    throw new TypeError('Array expected');
-	  }
-	  if (index.length != this._size.length) {
-	    throw new DimensionError(index.length, this._size.length);
-	  }
-
-	  var data = this._data;
-	  for (var i = 0, ii = index.length; i < ii; i++) {
-	    var index_i = index[i];
-	    validateIndex(index_i, data.length);
-	    data = data[index_i];
-	  }
-
-	  return object.clone(data);
-	};
-
-	/**
-	 * Replace a single element in the matrix.
-	 * @param {Number[]} index   Zero-based index
-	 * @param {*} value
-	 * @param {*} [defaultValue]        Default value, filled in on new entries when
-	 *                                  the matrix is resized. If not provided,
-	 *                                  new matrix elements will be left undefined.
-	 * @return {Matrix} self
-	 */
-	Matrix.prototype.set = function (index, value, defaultValue) {
-	  var i, ii;
-
-	  // validate input type and dimensions
-	  if (!isArray(index)) {
-	    throw new Error('Array expected');
-	  }
-	  if (index.length < this._size.length) {
-	    throw new DimensionError(index.length, this._size.length, '<');
-	  }
-
-	  // enlarge matrix when needed
-	  var size = index.map(function (i) {
-	    return i + 1;
-	  });
-	  _fit(this, size, defaultValue);
-
-	  // traverse over the dimensions
-	  var data = this._data;
-	  for (i = 0, ii = index.length - 1; i < ii; i++) {
-	    var index_i = index[i];
-	    validateIndex(index_i, data.length);
-	    data = data[index_i];
-	  }
-
-	  // set new value
-	  index_i = index[index.length - 1];
-	  validateIndex(index_i, data.length);
-	  data[index_i] = value;
-
-	  return this;
-	};
-
-	/**
-	 * Get a submatrix of this matrix
-	 * @param {Matrix} matrix
-	 * @param {Index} index   Zero-based index
-	 * @private
-	 */
-	function _get (matrix, index) {
-	  if (!(index instanceof Index)) {
-	    throw new TypeError('Invalid index');
-	  }
-
-	  var isScalar = index.isScalar();
-	  if (isScalar) {
-	    // return a scalar
-	    return matrix.get(index.min());
-	  }
-	  else {
-	    // validate dimensions
-	    var size = index.size();
-	    if (size.length != matrix._size.length) {
-	      throw new DimensionError(size.length, matrix._size.length);
-	    }
-
-	    // validate if any of the ranges in the index is out of range
-	    var min = index.min();
-	    var max = index.max();
-	    for (var i = 0, ii = matrix._size.length; i < ii; i++) {
-	      validateIndex(min[i], matrix._size[i]);
-	      validateIndex(max[i], matrix._size[i]);
-	    }
-
-	    // retrieve submatrix
-	    // TODO: more efficient when creating an empty matrix and setting _data and _size manually
-	    return new Matrix(_getSubmatrix(matrix._data, index, size.length, 0));
-	  }
-	}
-
-	/**
-	 * Recursively get a submatrix of a multi dimensional matrix.
-	 * Index is not checked for correct number or length of dimensions.
-	 * @param {Array} data
-	 * @param {Index} index
-	 * @param {number} dims   Total number of dimensions
-	 * @param {number} dim    Current dimension
-	 * @return {Array} submatrix
-	 * @private
-	 */
-	function _getSubmatrix (data, index, dims, dim) {
-	  var last = (dim == dims - 1);
-	  var range = index.range(dim);
-
-	  if (last) {
-	    return range.map(function (i) {
-	      return data[i];
-	    });
-	  }
-	  else {
-	    return range.map(function (i) {
-	      var child = data[i];
-	      return _getSubmatrix(child, index, dims, dim + 1);
-	    });
-	  }
-	}
-
-	/**
-	 * Replace a submatrix in this matrix
-	 * Indexes are zero-based.
-	 * @param {Matrix} matrix
-	 * @param {Index} index
-	 * @param {Matrix | Array | *} submatrix
-	 * @param {*} defaultValue          Default value, filled in on new entries when
-	 *                                  the matrix is resized.
-	 * @return {Matrix} matrix
-	 * @private
-	 */
-	function _set (matrix, index, submatrix, defaultValue) {
-	  if (!(index instanceof Index)) {
-	    throw new TypeError('Invalid index');
-	  }
-
-	  // get index size and check whether the index contains a single value
-	  var iSize = index.size(),
-	      isScalar = index.isScalar();
-
-	  // calculate the size of the submatrix, and convert it into an Array if needed
-	  var sSize;
-	  if (submatrix instanceof Matrix) {
-	    sSize = submatrix.size();
-	    submatrix = submatrix.valueOf();
-	  }
-	  else {
-	    sSize = array.size(submatrix);
-	  }
-
-	  if (isScalar) {
-	    // set a scalar
-
-	    // check whether submatrix is a scalar
-	    if (sSize.length != 0) {
-	      throw new TypeError('Scalar expected');
-	    }
-
-	    matrix.set(index.min(), submatrix, defaultValue);
-	  }
-	  else {
-	    // set a submatrix
-
-	    // validate dimensions
-	    if (iSize.length < matrix._size.length) {
-	      throw new DimensionError(iSize.length, matrix._size.length, '<');
-	    }
-
-	    if (sSize.length < iSize.length) {
-	      // calculate number of missing outer dimensions
-	      var i = 0;
-	      var outer = 0;
-	      while (iSize[i] === 1 && sSize[i] === 1) {
-	        i++;
-	      }
-	      while (iSize[i] === 1) {
-	        outer++;
-	        i++;
-	      }
-
-	      // unsqueeze both outer and inner dimensions
-	      submatrix = array.unsqueeze(submatrix, iSize.length, outer, sSize);
-	    }
-
-	    // check whether the size of the submatrix matches the index size
-	    if (!object.deepEqual(iSize, sSize)) {
-	      throw new DimensionError(iSize, sSize, '>');
-	    }
-
-	    // enlarge matrix when needed
-	    var size = index.max().map(function (i) {
-	      return i + 1;
-	    });
-	    _fit(matrix, size, defaultValue);
-
-	    // insert the sub matrix
-	    var dims = iSize.length,
-	        dim = 0;
-	    _setSubmatrix (matrix._data, index, submatrix, dims, dim);
-	  }
-
-	  return matrix;
-	}
-
-	/**
-	 * Replace a submatrix of a multi dimensional matrix.
-	 * @param {Array} data
-	 * @param {Index} index
-	 * @param {Array} submatrix
-	 * @param {number} dims   Total number of dimensions
-	 * @param {number} dim
-	 * @private
-	 */
-	function _setSubmatrix (data, index, submatrix, dims, dim) {
-	  var last = (dim == dims - 1),
-	      range = index.range(dim);
-
-	  if (last) {
-	    range.forEach(function (dataIndex, subIndex) {
-	      validateIndex(dataIndex);
-	      data[dataIndex] = submatrix[subIndex];
-	    });
-	  }
-	  else {
-	    range.forEach(function (dataIndex, subIndex) {
-	      validateIndex(dataIndex);
-	      _setSubmatrix(data[dataIndex], index, submatrix[subIndex], dims, dim + 1);
-	    });
-	  }
-	}
-
-	/**
-	 * Resize the matrix
-	 * @param {Number[]} size
-	 * @param {*} [defaultValue=0]      Default value, filled in on new entries.
-	 *                                  If not provided, the matrix elements will
-	 *                                  be filled with zeros.
-	 * @return {Matrix} self            The matrix itself is returned
-	 */
-	Matrix.prototype.resize = function (size, defaultValue) {
-	  this._size = object.clone(size);
-	  this._data = array.resize(this._data, this._size, defaultValue);
-
-	  // return the matrix itself
-	  return this;
-	};
-
-	/**
-	 * Enlarge the matrix when it is smaller than given size.
-	 * If the matrix is larger or equal sized, nothing is done.
-	 * @param {Matrix} matrix           The matrix to be resized
-	 * @param {Number[]} size
-	 * @param {*} defaultValue          Default value, filled in on new entries.
-	 * @private
-	 */
-	function _fit(matrix, size, defaultValue) {
-	  var newSize = object.clone(matrix._size),
-	      changed = false;
-
-	  // add dimensions when needed
-	  while (newSize.length < size.length) {
-	    newSize.push(0);
-	    changed = true;
-	  }
-
-	  // enlarge size when needed
-	  for (var i = 0, ii = size.length; i < ii; i++) {
-	    if (size[i] > newSize[i]) {
-	      newSize[i] = size[i];
-	      changed = true;
-	    }
-	  }
-
-	  if (changed) {
-	    // resize only when size is changed
-	    matrix.resize(newSize, defaultValue);
-	  }
-	}
-
-	/**
-	 * 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.
-	 * @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 function 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 recurse = function (value, index) {
-	    if (isArray(value)) {
-	      return value.map(function (child, i) {
-	        return recurse(child, index.concat(i));
-	      });
-	    }
-	    else {
-	      return callback(value, index, me);
-	    }
-	  };
-	  matrix._data = recurse(this._data, []);
-	  matrix._size = object.clone(this._size);
-
-	  return matrix;
-	};
-
-	/**
-	 * Execute a callback function on each entry of the matrix.
-	 * @param {function} callback   The callback function 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 recurse = function (value, index) {
-	    if (isArray(value)) {
-	      value.forEach(function (child, i) {
-	        recurse(child, index.concat(i));
-	      });
-	    }
-	    else {
-	      callback(value, index, me);
-	    }
-	  };
-	  recurse(this._data, []);
-	};
-
-	/**
-	 * 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, with optional formatting options.
-	 * @param {Object | Number | Function} [options]  Formatting options. See
-	 *                                                lib/util/number:format for a
-	 *                                                description of the available
-	 *                                                options.
-	 * @returns {String} str
-	 */
-	Matrix.prototype.format = function (options) {
-	  return string.format(this._data, options);
-	};
-
-	/**
-	 * Get a string representation of the matrix
-	 * @returns {String} str
-	 */
-	Matrix.prototype.toString = function () {
-	  return string.format(this._data);
-	};
-
-	/**
-	 * Get a JSON representation of the matrix
-	 * @returns {Object}
-	 */
-	Matrix.prototype.toJSON = function () {
-	  return {
-	    mathjs: 'Matrix',
-	    data: this._data
-	  }
-	};
-
-	/**
-	 * Generate a matrix from a JSON object
-	 * @param {Object} json  An object structured like
-	 *                       `{"mathjs": "Matrix", data: []}`,
-	 *                       where mathjs is optional
-	 * @returns {Matrix}
-	 */
-	Matrix.fromJSON = function (json) {
-	  return new Matrix(json.data);
-	};
-
-	/**
-	 * Preprocess data, which can be an Array or Matrix with nested Arrays and
-	 * Matrices. Replaces all nested Matrices with Arrays
-	 * @param {Array} data
-	 * @return {Array} data
-	 */
-	function preprocess(data) {
-	  for (var i = 0, ii = data.length; i < ii; i++) {
-	    var elem = data[i];
-	    if (isArray(elem)) {
-	      data[i] = preprocess(elem);
-	    }
-	    else if (elem instanceof Matrix) {
-	      data[i] = preprocess(elem._data);
-	    }
-	  }
-
-	  return data;
-	}
-
-	// exports
-	module.exports = Matrix;
-
+	var string = __webpack_require__(175),
+
+	    isString = string.isString;
+
+	module.exports = function (config) {
+
+	  /**
+	   * @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 = math.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 function valueOf.
+	   *
+	   * Example usage:
+	   *     var matrix = math.matrix([[1, 2], [3, 4]]);
+	   *     matix.size();              // [2, 2]
+	   *     matrix.resize([3, 2], 5);
+	   *     matrix.valueOf();          // [[1, 2], [3, 4], [5, 5]]
+	   *     matrix.subset([1,2])       // 3 (indexes are zero-based)
+	   *
+	   */
+	  function Matrix() {
+	    if (!(this instanceof Matrix)) {
+	      throw new SyntaxError('Constructor must be called with the new operator');
+	    }
+	  }
+
+	  /**
+	   * Test whether an object is a Matrix
+	   * @param {*} object
+	   * @return {Boolean} isMatrix
+	   */
+	  Matrix.isMatrix = function (object) {
+	    return (object instanceof Matrix);
+	  };
+
+	  /**
+	   * Get the Matrix storage constructor for the given format.
+	   *
+	   * @param {string} format       The Matrix storage format.
+	   *
+	   * @return {Function}           The Matrix storage constructor.
+	   */
+	  Matrix.storage = function (format) {
+	    // check storage format is a string
+	    if (!isString(format)) {
+	      throw new TypeError('format must be a string value');
+	    }
+
+	    // get storage format constructor
+	    var constructor = Matrix._storage[format];
+	    if (!constructor) {
+	      throw new SyntaxError('Unsupported matrix storage format: ' + format);
+	    }
+
+	    // return storage constructor
+	    return constructor;
+	  };
+
+	  // a map with all constructors for all storage types
+	  Matrix._storage = {};
+
+	  /**
+	   * Get the storage format used by the matrix.
+	   *
+	   * Usage:
+	   *     var format = matrix.storage()                   // retrieve storage format
+	   *
+	   * @return {string}           The storage format.
+	   */
+	  Matrix.prototype.storage = function () {
+	    // must be implemented by each of the Matrix implementations
+	    throw new Error('Cannot invoke storage on a Matrix interface');
+	  };
+	  
+	  /**
+	   * Get a subset of the matrix, or replace a subset of the matrix.
+	   *
+	   * Usage:
+	   *     var subset = matrix.subset(index)               // retrieve subset
+	   *     var value = matrix.subset(index, replacement)   // replace subset
+	   *
+	   * @param {Index} index
+	   * @param {Array | Matrix | *} [replacement]
+	   * @param {*} [defaultValue=0]      Default value, filled in on new entries when
+	   *                                  the matrix is resized. If not provided,
+	   *                                  new matrix elements will be filled with zeros.
+	   */
+	  Matrix.prototype.subset = function (index, replacement, defaultValue) {
+	    // must be implemented by each of the Matrix implementations
+	    throw new Error('Cannot invoke subset on a Matrix interface');
+	  };
+
+	  /**
+	   * Get a single element from the matrix.
+	   * @param {Number[]} index   Zero-based index
+	   * @return {*} value
+	   */
+	  Matrix.prototype.get = function (index) {
+	    // must be implemented by each of the Matrix implementations
+	    throw new Error('Cannot invoke get on a Matrix interface');
+	  };
+
+	  /**
+	   * Replace a single element in the matrix.
+	   * @param {Number[]} index   Zero-based index
+	   * @param {*} value
+	   * @param {*} [defaultValue]        Default value, filled in on new entries when
+	   *                                  the matrix is resized. If not provided,
+	   *                                  new matrix elements will be left undefined.
+	   * @return {Matrix} self
+	   */
+	  Matrix.prototype.set = function (index, value, defaultValue) {
+	    // must be implemented by each of the Matrix implementations
+	    throw new Error('Cannot invoke set on a Matrix interface');
+	  };
+
+	  /**
+	   * Resize the matrix to the given size. Returns a copy of the matrix when 
+	   * `copy=true`, otherwise return the matrix itself (resize in place).
+	   *
+	   * @param {Number[]} size           The new size the matrix should have.
+	   * @param {*} [defaultValue=0]      Default value, filled in on new entries.
+	   *                                  If not provided, the matrix elements will
+	   *                                  be filled with zeros.
+	   * @param {boolean} [copy]          Return a resized copy of the matrix
+	   *
+	   * @return {Matrix}                 The resized matrix
+	   */
+	  Matrix.prototype.resize = function (size, defaultValue) {
+	    // must be implemented by each of the Matrix implementations
+	    throw new Error('Cannot invoke resize on a Matrix interface');
+	  };
+
+	  /**
+	   * Create a clone of the matrix
+	   * @return {Matrix} clone
+	   */
+	  Matrix.prototype.clone = function () {
+	    // must be implemented by each of the Matrix implementations
+	    throw new Error('Cannot invoke clone on a Matrix interface');
+	  };
+
+	  /**
+	   * Retrieve the size of the matrix.
+	   * @returns {Number[]} size
+	   */
+	  Matrix.prototype.size = function() {
+	    // must be implemented by each of the Matrix implementations
+	    throw new Error('Cannot invoke size on a Matrix interface');
+	  };
+
+	  /**
+	   * Create a new matrix with the results of the callback function executed on
+	   * each entry of the matrix.
+	   * @param {function} callback   The callback function is invoked with three
+	   *                              parameters: the value of the element, the index
+	   *                              of the element, and the Matrix being traversed.
+	   * @param {boolean} [skipZeros] Invoke callback function for non-zero values only.
+	   *
+	   * @return {Matrix} matrix
+	   */
+	  Matrix.prototype.map = function (callback, skipZeros) {
+	    // must be implemented by each of the Matrix implementations
+	    throw new Error('Cannot invoke map on a Matrix interface');
+	  };
+
+	  /**
+	   * Execute a callback function on each entry of the matrix.
+	   * @param {function} callback   The callback function 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) {
+	    // must be implemented by each of the Matrix implementations
+	    throw new Error('Cannot invoke forEach on a Matrix interface');
+	  };
+
+	  /**
+	   * Create an Array with a copy of the data of the Matrix
+	   * @returns {Array} array
+	   */
+	  Matrix.prototype.toArray = function () {
+	    // must be implemented by each of the Matrix implementations
+	    throw new Error('Cannot invoke toArray on a Matrix interface');
+	  };
+
+	  /**
+	   * Get the primitive value of the Matrix: a multidimensional array
+	   * @returns {Array} array
+	   */
+	  Matrix.prototype.valueOf = function () {
+	    // must be implemented by each of the Matrix implementations
+	    throw new Error('Cannot invoke valueOf on a Matrix interface');
+	  };
+
+	  /**
+	   * Get a string representation of the matrix, with optional formatting options.
+	   * @param {Object | Number | Function} [options]  Formatting options. See
+	   *                                                lib/util/number:format for a
+	   *                                                description of the available
+	   *                                                options.
+	   * @returns {String} str
+	   */
+	  Matrix.prototype.format = function (options) {
+	    // must be implemented by each of the Matrix implementations
+	    throw new Error('Cannot invoke format on a Matrix interface');
+	  };
+
+	  /**
+	   * Get a string representation of the matrix
+	   * @returns {String} str
+	   */
+	  Matrix.prototype.toString = function () {
+	    // must be implemented by each of the Matrix implementations
+	    throw new Error('Cannot invoke toString on a Matrix interface');
+	  };
+
+	  /**
+	   * Calculates the transpose of the matrix
+	   * @returns {Matrix}
+	   */
+	  Matrix.prototype.transpose = function () {
+	    // must be implemented by each of the Matrix implementations
+	    throw new Error('Cannot invoke transpose on a Matrix interface');
+	  };
+
+	  /**
+	   * Calculate the trace of a matrix: the sum of the elements on the main
+	   * diagonal of a square matrix.
+	   *
+	   * See also:
+	   *
+	   *    diagonal
+	   *
+	   * @returns {Number}       The matrix trace
+	   */
+	  Matrix.prototype.trace = function () {
+	    // must be implemented by each of the Matrix implementations
+	    throw new Error('Cannot invoke transpose on a Matrix interface');
+	  };
+
+	  /**
+	   * Multiply the matrix values times the argument.
+	   *
+	   * @param  {Number | BigNumber | Boolean | Complex | Unit | Array | Matrix | null} Value to multiply.
+	   *
+	   * @return {Number | BigNumber | Complex | Unit | Matrix}
+	   */
+	  Matrix.prototype.multiply = function (value) {
+	    // must be implemented by each of the Matrix implementations
+	    throw new Error('Cannot invoke multiply on a Matrix interface');
+	  };
+	  
+	  // exports
+	  return Matrix;
+	};
 
 /***/ },
 /* 11 */
@@ -2698,7 +2533,7 @@
 
 	'use strict';
 
-	var util = __webpack_require__(171),
+	var util = __webpack_require__(174),
 
 	    number = util.number,
 	    string = util.string,
@@ -3442,6 +3277,7 @@
 	  poundmass: {name: 'poundmass', base: BASE_UNITS.MASS, prefixes: PREFIXES.NONE, value: 453.59237e-3, offset: 0},
 	  hundredweight: {name: 'hundredweight', base: BASE_UNITS.MASS, prefixes: PREFIXES.NONE, value: 45.359237, offset: 0},
 	  stick: {name: 'stick', base: BASE_UNITS.MASS, prefixes: PREFIXES.NONE, value: 115e-3, offset: 0},
+	  stone: {name: 'stone', base: BASE_UNITS.MASS, prefixes: PREFIXES.NONE, value: 6350, offset: 0},
 
 	  gr: {name: 'gr', base: BASE_UNITS.MASS, prefixes: PREFIXES.NONE, value: 64.79891e-6, offset: 0},
 	  dr: {name: 'dr', base: BASE_UNITS.MASS, prefixes: PREFIXES.NONE, value: 1.7718451953125e-3, offset: 0},
@@ -3473,9 +3309,9 @@
 	  ampere: {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
+	  // K(C) = °C + 273.15
+	  // K(F) = (°F + 459.67) / 1.8
+	  // K(R) = °R / 1.8
 	  K: {name: 'K', base: BASE_UNITS.TEMPERATURE, prefixes: PREFIXES.NONE, value: 1, offset: 0},
 	  degC: {name: 'degC', base: BASE_UNITS.TEMPERATURE, prefixes: PREFIXES.NONE, value: 1, offset: 273.15},
 	  degF: {name: 'degF', base: BASE_UNITS.TEMPERATURE, prefixes: PREFIXES.NONE, value: 1/1.8, offset: 459.67},
@@ -3596,7 +3432,7 @@
 
 	'use strict';
 
-	var util = __webpack_require__(171);
+	var util = __webpack_require__(174);
 	var object = util.object;
 	var string = util.string;
 
@@ -3790,265 +3626,272 @@
 	// utility methods for arrays and matrices
 	'use strict';
 
-	var util = __webpack_require__(171),
-
-	    IndexError = __webpack_require__(169),
-	    DimensionError = __webpack_require__(168),
-
-	    Matrix = __webpack_require__(10),
+	var util = __webpack_require__(174),
+
+	    IndexError = __webpack_require__(172),
+	    DimensionError = __webpack_require__(171),
 
 	    array = util.array,
-	    isArray = util.array.isArray,
-	    isString = util.string.isString;
-
-	/**
-	 * 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(args) {
-	  if (args.length == 0) {
-	    // fn()
-	    return [];
-	  }
-	  else if (args.length == 1) {
-	    // fn(n)
-	    // fn([m, n, p, ...])
-	    var array = args[0];
+	    isArray = util.array.isArray;
+
+	module.exports = function (math) {
+
+	  var Matrix = math.type.Matrix;
+
+	  var collection = {};
+
+	  /**
+	   * 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
+	   */
+	  collection.argsToArray = function(args) {
+	    if (args.length === 0) {
+	      // fn()
+	      return [];
+	    }
+	    else if (args.length == 1) {
+	      // fn(n)
+	      // fn([m, n, p, ...])
+	      var array = args[0];
+	      if (array instanceof Matrix) {
+	        array = array.valueOf();
+	      }
+	      if (!isArray(array)) {
+	        array = [array];
+	      }
+	      return array;
+	    }
+	    else {
+	      // fn(m, n, p, ...)
+	      return util.array.argsToArray(args);
+	    }
+	  };
+
+
+	  /**
+	   * Test whether a value is a collection: an Array or Matrix
+	   * @param {*} x
+	   * @returns {boolean} isCollection
+	   */
+	  collection.isCollection = function(x) {
+	    return (isArray(x) || (x instanceof Matrix));
+	  };
+
+	  /**
+	   * Execute the callback function element wise for each element in array and any
+	   * nested array
+	   * Returns an array with the results
+	   * @param {Array | Matrix} array
+	   * @param {function} callback   The callback is called with two parameters:
+	   *                              value1 and value2, which contain the current
+	   *                              element of both arrays.
+	   * @param {boolean} [skipZeros] Invoke callback function for non-zero values only.
+	   *
+	   * @return {Array | Matrix} res
+	   */
+	  collection.deepMap = function deepMap(array, callback, skipZeros) {
+	    if (array && (typeof array.map === 'function')) {
+	      return array.map(function (x) {
+	        return deepMap(x, callback, skipZeros);
+	      });
+	    }
+	    else {
+	      return callback(array);
+	    }
+	  };
+
+	  /**
+	   * Execute the callback function 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 | Object} array1
+	   * @param {Array | Matrix | Object} array2
+	   * @param {function} callback   The callback is called with two parameters:
+	   *                              value1 and value2, which contain the current
+	   *                              element of both arrays.
+	   * @return {Array | Matrix} res
+	   */
+	  collection.deepMap2 = function deepMap2(array1, array2, callback) {
+	    var res, len, i;
+
+	    if (isArray(array1)) {
+	      if (isArray(array2)) {
+	        // callback(array, array)
+	        if (array1.length != array2.length) {
+	          throw new DimensionError(array1.length, array2.length);
+	        }
+
+	        res = [];
+	        len = array1.length;
+	        for (i = 0; i < len; i++) {
+	          res[i] = deepMap2(array1[i], array2[i], callback);
+	        }
+	      }
+	      else if (array2 instanceof Matrix) {
+	        // callback(array, matrix)
+	        res = deepMap2(array1, array2.valueOf(), callback);
+	        return math.matrix(res);
+	      }
+	      else {
+	        // callback(array, object)
+	        res = [];
+	        len = array1.length;
+	        for (i = 0; i < len; i++) {
+	          res[i] = deepMap2(array1[i], array2, callback);
+	        }
+	      }
+	    }
+	    else if (array1 instanceof Matrix) {
+	      if (array2 instanceof Matrix) {
+	        // callback(matrix, matrix)
+	        res = deepMap2(array1.valueOf(), array2.valueOf(), callback);
+	        return math.matrix(res);
+	      }
+	      else {
+	        // callback(matrix, array)
+	        // callback(matrix, object)
+	        res = deepMap2(array1.valueOf(), array2, callback);
+	        return math.matrix(res);
+	      }
+	    }
+	    else {
+	      if (isArray(array2)) {
+	        // callback(object, array)
+	        res = [];
+	        len = array2.length;
+	        for (i = 0; i < len; i++) {
+	          res[i] = deepMap2(array1, array2[i], callback);
+	        }
+	      }
+	      else if (array2 instanceof Matrix) {
+	        // callback(object, matrix)
+	        res = deepMap2(array1, array2.valueOf(), callback);
+	        return math.matrix(res);
+	      }
+	      else {
+	        // callback(object, object)
+	        res = callback(array1, array2);
+	      }
+	    }
+
+	    return res;
+	  };
+
+	  /**
+	   * Reduce a given matrix or array to a new matrix or
+	   * array with one less dimension, applying the given
+	   * callback in the selected dimension.
+	   * @param {Array | Matrix} mat
+	   * @param {Number} dim
+	   * @param {function} callback
+	   * @return {Array | Matrix} res
+	   */
+	  collection.reduce = function(mat, dim, callback) {
+	    var size = isArray(mat) ? array.size(mat) : mat.size();
+	    if (dim < 0) {
+	      // TODO: would be more clear when throwing a DimensionError here
+	      throw new IndexError(dim);
+	    }
+	    if (dim >= size.length) {
+	      // TODO: would be more clear when throwing a DimensionError here
+	      throw new IndexError(dim, size.length);
+	    }
+
+	      if (mat instanceof Matrix) {
+	          return math.matrix(_reduce(mat.valueOf(), dim, callback));
+	      }else {
+	          return _reduce(mat, dim, callback);
+	      }
+	  };
+
+	  /**
+	   * Recursively reduce a matrix
+	   * @param {Array} mat
+	   * @param {Number} dim
+	   * @param {Function} callback
+	   * @returns {Array} ret
+	   * @private
+	   */
+	  function _reduce(mat, dim, callback){
+	    var i, ret, val, tran;
+
+	      if(dim<=0){
+	          if( !isArray(mat[0]) ){
+	              val = mat[0];
+	              for(i=1; i<mat.length; i++){
+	                  val = callback(val, mat[i]);
+	              }
+	              return val;
+	          }else{
+	              tran = _switch(mat);
+	              ret = [];
+	              for(i=0; i<tran.length; i++){
+	                  ret[i] = _reduce(tran[i], dim-1, callback);
+	              }
+	              return ret;
+	          }
+	      }else{
+	          ret = [];
+	          for(i=0; i<mat.length; i++){
+	              ret[i] = _reduce(mat[i], dim-1, callback);
+	          }
+	          return ret;
+	      }
+	  }
+
+	  /**
+	   * Transpose a matrix
+	   * @param {Array} mat
+	   * @returns {Array} ret
+	   * @private
+	   */
+	  function _switch(mat){
+	    var I = mat.length;
+	    var J = mat[0].length;
+	    var i, j;
+	    var ret = [];
+	    for( j=0; j<J; j++) {
+	      var tmp = [];
+	      for( i=0; i<I; i++) {
+	        tmp.push(mat[i][j]);
+	      }
+	      ret.push(tmp);
+	    }
+	    return ret;
+	  }
+
+	  /**
+	   * Recursively loop over all elements in a given multi dimensional array
+	   * and invoke the callback on each of the elements.
+	   * @param {Array | Matrix} array
+	   * @param {function} callback     The callback method is invoked with one
+	   *                                parameter: the current element in the array
+	   */
+	  collection.deepForEach = function deepForEach (array, callback) {
 	    if (array instanceof Matrix) {
 	      array = array.valueOf();
 	    }
-	    if (!isArray(array)) {
-	      array = [array];
-	    }
-	    return array;
-	  }
-	  else {
-	    // fn(m, n, p, ...)
-	    return util.array.argsToArray(args);
-	  }
-	};
-
-
-	/**
-	 * Test whether a value is a collection: an Array or Matrix
-	 * @param {*} x
-	 * @returns {boolean} isCollection
-	 */
-	exports.isCollection = function(x) {
-	  return (isArray(x) || (x instanceof Matrix));
-	};
-
-	/**
-	 * Execute the callback function element wise for each element in array and any
-	 * nested array
-	 * Returns an array with the results
-	 * @param {Array | Matrix} array
-	 * @param {function} callback   The callback is called with two parameters:
-	 *                              value1 and value2, which contain the current
-	 *                              element of both arrays.
-	 * @return {Array | Matrix} res
-	 */
-	exports.deepMap = function deepMap(array, callback) {
-	  if (array && (typeof array.map === 'function')) {
-	    return array.map(function (x) {
-	      return deepMap(x, callback);
-	    });
-	  }
-	  else {
-	    return callback(array);
-	  }
-	};
-
-	/**
-	 * Execute the callback function 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 | Object} array1
-	 * @param {Array | Matrix | Object} array2
-	 * @param {function} callback   The callback is called with two parameters:
-	 *                              value1 and value2, which contain the current
-	 *                              element of both arrays.
-	 * @return {Array | Matrix} res
-	 */
-	exports.deepMap2 = function deepMap2(array1, array2, callback) {
-	  var res, len, i;
-
-	  if (isArray(array1)) {
-	    if (isArray(array2)) {
-	      // callback(array, array)
-	      if (array1.length != array2.length) {
-	        throw new DimensionError(array1.length, array2.length);
-	      }
-
-	      res = [];
-	      len = array1.length;
-	      for (i = 0; i < len; i++) {
-	        res[i] = deepMap2(array1[i], array2[i], callback);
-	      }
-	    }
-	    else if (array2 instanceof Matrix) {
-	      // callback(array, matrix)
-	      res = deepMap2(array1, array2.valueOf(), callback);
-	      return new Matrix(res);
-	    }
-	    else {
-	      // callback(array, object)
-	      res = [];
-	      len = array1.length;
-	      for (i = 0; i < len; i++) {
-	        res[i] = deepMap2(array1[i], array2, callback);
-	      }
-	    }
-	  }
-	  else if (array1 instanceof Matrix) {
-	    if (array2 instanceof Matrix) {
-	      // callback(matrix, matrix)
-	      res = deepMap2(array1.valueOf(), array2.valueOf(), callback);
-	      return new Matrix(res);
-	    }
-	    else {
-	      // callback(matrix, array)
-	      // callback(matrix, object)
-	      res = deepMap2(array1.valueOf(), array2, callback);
-	      return new Matrix(res);
-	    }
-	  }
-	  else {
-	    if (isArray(array2)) {
-	      // callback(object, array)
-	      res = [];
-	      len = array2.length;
-	      for (i = 0; i < len; i++) {
-	        res[i] = deepMap2(array1, array2[i], callback);
-	      }
-	    }
-	    else if (array2 instanceof Matrix) {
-	      // callback(object, matrix)
-	      res = deepMap2(array1, array2.valueOf(), callback);
-	      return new Matrix(res);
-	    }
-	    else {
-	      // callback(object, object)
-	      res = callback(array1, array2);
-	    }
-	  }
-
-	  return res;
-	};
-
-	/**
-	 * Reduce a given matrix or array to a new matrix or
-	 * array with one less dimension, applying the given
-	 * callback in the selected dimension.
-	 * @param {Array | Matrix} mat
-	 * @param {Number} dim
-	 * @param {function} callback
-	 * @return {Array | Matrix} res
-	 */
-	exports.reduce = function(mat, dim, callback) {
-	  var size = isArray(mat) ? array.size(mat) : mat.size();
-	  if (dim < 0) {
-	    // TODO: would be more clear when throwing a DimensionError here
-	    throw new IndexError(dim);
-	  }
-	  if (dim >= size.length) {
-	    // TODO: would be more clear when throwing a DimensionError here
-	    throw new IndexError(dim, size.length);
-	  }
-
-		if (mat instanceof Matrix) {
-			return new Matrix(_reduce(mat.valueOf(), dim, callback));
-		}else {
-			return _reduce(mat, dim, callback);
-		}
-	};
-
-	/**
-	 * Recursively reduce a matrix
-	 * @param {Array} mat
-	 * @param {Number} dim
-	 * @param {Function} callback
-	 * @returns {Array} ret
-	 * @private
-	 */
-	function _reduce(mat, dim, callback){
-	  var i, ret, val, tran;
-
-		if(dim<=0){
-			if( !isArray(mat[0]) ){
-				val = mat[0];
-				for(i=1; i<mat.length; i++){
-					val = callback(val, mat[i]);
-				}
-				return val;
-			}else{
-				tran = _switch(mat);
-				ret = [];
-				for(i=0; i<tran.length; i++){
-					ret[i] = _reduce(tran[i], dim-1, callback);
-				}
-				return ret
-			}
-		}else{
-			ret = [];
-			for(i=0; i<mat.length; i++){
-				ret[i] = _reduce(mat[i], dim-1, callback);
-			}
-			return ret;
-		}
-	}
-
-	/**
-	 * Transpose a matrix
-	 * @param {Array} mat
-	 * @returns {Array} ret
-	 * @private
-	 */
-	function _switch(mat){
-	  var I = mat.length;
-	  var J = mat[0].length;
-	  var i, j;
-	  var ret = [];
-	  for( j=0; j<J; j++) {
-	    var tmp = [];
-	    for( i=0; i<I; i++) {
-	      tmp.push(mat[i][j]);
-	    }
-	    ret.push(tmp);
-	  }
-	  return ret;
-	}
-
-	/**
-	 * Recursively loop over all elements in a given multi dimensional array
-	 * and invoke the callback on each of the elements.
-	 * @param {Array | Matrix} array
-	 * @param {function} callback     The callback method is invoked with one
-	 *                                parameter: the current element in the array
-	 */
-	exports.deepForEach = function deepForEach (array, callback) {
-	  if (array instanceof Matrix) {
-	    array = array.valueOf();
-	  }
-
-	  for (var i = 0, ii = array.length; i < ii; i++) {
-	    var value = array[i];
-
-	    if (isArray(value)) {
-	      deepForEach(value, callback);
-	    }
-	    else {
-	      callback(value);
-	    }
-	  }
-	};
-
+
+	    for (var i = 0, ii = array.length; i < ii; i++) {
+	      var value = array[i];
+
+	      if (isArray(value)) {
+	        deepForEach(value, callback);
+	      }
+	      else {
+	        callback(value);
+	      }
+	    }
+	  };
+	  
+	  return collection;
+	};
 
 /***/ },
 /* 15 */
@@ -4056,20 +3899,1214 @@
 
 	'use strict';
 
-	exports.ArrayNode = __webpack_require__(172);
-	exports.AssignmentNode = __webpack_require__(173);
-	exports.BlockNode = __webpack_require__(174);
-	exports.ConditionalNode = __webpack_require__(175);
-	exports.ConstantNode = __webpack_require__(176);
-	exports.IndexNode = __webpack_require__(177);
-	exports.FunctionAssignmentNode = __webpack_require__(178);
-	exports.FunctionNode = __webpack_require__(179);
-	exports.Node = __webpack_require__(180);
-	exports.OperatorNode = __webpack_require__(181);
-	exports.RangeNode = __webpack_require__(182);
-	exports.SymbolNode = __webpack_require__(183);
-	exports.UpdateNode = __webpack_require__(184);
-
+	var util = __webpack_require__(174);
+	var DimensionError = __webpack_require__(171);
+
+	var array = util.array;
+	var object = util.object;
+	var string = util.string;
+	var number = util.number;
+
+	var isArray = Array.isArray;
+	var isNumber = util.number.isNumber;
+	var isInteger = util.number.isInteger;
+
+	var validateIndex = array.validateIndex;
+
+	module.exports = function (math) {
+	  
+	  var Index = math.type.Index,
+	      BigNumber = math.type.BigNumber,
+	      Matrix = math.type.Matrix;
+	  
+	  function CcsMatrix(data) {
+	    if (!(this instanceof CcsMatrix))
+	      throw new SyntaxError('Constructor must be called with the new operator');
+
+	    if (data instanceof Matrix) {
+	      // check data is a CcsMatrix
+	      if (data.type === 'CcsMatrix') {
+	        // clone arrays
+	        this._values = object.clone(data._values);
+	        this._index = object.clone(data._index);
+	        this._ptr = object.clone(data._ptr);
+	        this._size = object.clone(data._size);
+	      }
+	      else {
+	        // build from matrix data
+	        _createFromArray(this, data.valueOf());
+	      }
+	    }
+	    else if (data && isArray(data.values) && isArray(data.index) && isArray(data.ptr) && isArray(data.size)) {
+	      // initialize fields
+	      this._values = data.values;
+	      this._index = data.index;
+	      this._ptr = data.ptr;
+	      this._size = data.size;
+	    }
+	    else if (isArray(data)) {
+	      // create from array
+	      _createFromArray(this, data);
+	    }
+	    else if (data) {
+	      // unsupported type
+	      throw new TypeError('Unsupported type of data (' + util.types.type(data) + ')');
+	    }
+	    else {
+	      // nothing provided
+	      this._values = [];
+	      this._index = [];
+	      this._ptr = [0];
+	      this._size = [0];
+	    }
+	  }
+	  
+	  var _createFromArray = function (matrix, data) {
+	    // initialize fields
+	    matrix._values = [];
+	    matrix._index = [];
+	    matrix._ptr = [];
+	    // discover rows & columns, do not use math.size() to avoid looping array twice
+	    var rows = data.length;
+	    var columns = 0;
+
+	    // check we have rows (empty array)
+	    if (rows > 0) {
+	      // column index
+	      var j = 0;
+	      do {
+	        // store pointer to values index
+	        matrix._ptr.push(matrix._values.length);
+	        // loop rows
+	        for (var i = 0; i < rows; i++) {
+	          // current row
+	          var row = data[i];
+	          // check row is an array
+	          if (isArray(row)) {
+	            // update columns if needed (only on first column)
+	            if (j ===0 && columns < row.length)
+	              columns = row.length;
+	            // check row has column
+	            if (j < row.length) {
+	              // value
+	              var v = row[j];
+	              // check value != 0
+	              if (!math.equal(v, 0)) {
+	                // store value
+	                matrix._values.push(v);
+	                // index
+	                matrix._index.push(i);
+	              }
+	            }
+	          }
+	          else {
+	            // update columns if needed (only on first column)
+	            if (j === 0 && columns < 1)
+	              columns = 1;
+	            // check value != 0 (row is a scalar)
+	            if (!math.equal(row, 0)) {
+	              // store value
+	              matrix._values.push(row);
+	              // index
+	              matrix._index.push(i);
+	            }
+	          }
+	        }
+	        // increment index
+	        j++;      
+	      }
+	      while (j < columns);
+	    }
+	    // store number of values in ptr
+	    matrix._ptr.push(matrix._values.length);
+	    // size
+	    matrix._size = [rows, columns];
+	  };
+	  
+	  CcsMatrix.prototype = new math.type.Matrix();
+
+	  CcsMatrix.prototype.type = 'CcsMatrix';
+	  
+	  /**
+	   * Get the storage format used by the matrix.
+	   *
+	   * Usage:
+	   *     var format = matrix.storage()                   // retrieve storage format
+	   *
+	   * @return {string}           The storage format.
+	   */
+	  CcsMatrix.prototype.storage = function () {
+	    return 'ccs';
+	  };
+	  
+	  /**
+	   * Get a subset of the matrix, or replace a subset of the matrix.
+	   *
+	   * Usage:
+	   *     var subset = matrix.subset(index)               // retrieve subset
+	   *     var value = matrix.subset(index, replacement)   // replace subset
+	   *
+	   * @param {Index} index
+	   * @param {Array | Maytrix | *} [replacement]
+	   * @param {*} [defaultValue=0]      Default value, filled in on new entries when
+	   *                                  the matrix is resized. If not provided,
+	   *                                  new matrix elements will be filled with zeros.
+	   */
+	  CcsMatrix.prototype.subset = function (index, replacement, defaultValue) {
+	    // check arguments
+	    switch (arguments.length) {
+	      case 1:
+	        return _getsubset(this, index);
+
+	        // intentional fall through
+	      case 2:
+	      case 3:
+	        return _setsubset(this, index, replacement, defaultValue);
+
+	      default:
+	        throw new SyntaxError('Wrong number of arguments');
+	    }
+	  };
+	  
+	  var _getsubset = function (matrix, index) {
+	    // check index
+	    if (!(index instanceof Index)) {
+	      throw new TypeError('Invalid index');
+	    }
+
+	    var isScalar = index.isScalar();
+	    if (isScalar) {
+	      // return a scalar
+	      return matrix.get(index.min());
+	    }
+	    // validate dimensions
+	    var size = index.size();
+	    if (size.length != matrix._size.length) {
+	      throw new DimensionError(size.length, matrix._size.length);
+	    }
+
+	    // validate if any of the ranges in the index is out of range
+	    var min = index.min();
+	    var max = index.max();
+	    for (var i = 0, ii = matrix._size.length; i < ii; i++) {
+	      validateIndex(min[i], matrix._size[i]);
+	      validateIndex(max[i], matrix._size[i]);
+	    }
+
+	    // map callback
+	    var callback = function (v) {
+	      // return value
+	      return v;
+	    };
+	    // get sub-matrix
+	    return _map(matrix, min[0], max[0], min[1], max[1], callback, false);
+	  };
+	  
+	  var _setsubset = function (matrix, index, submatrix, defaultValue) {
+	    // check index
+	    if (!(index instanceof Index)) {
+	      throw new TypeError('Invalid index');
+	    }
+	    
+	    // get index size and check whether the index contains a single value
+	    var iSize = index.size(),
+	        isScalar = index.isScalar();
+	    
+	    // calculate the size of the submatrix, and convert it into an Array if needed
+	    var sSize;
+	    if (submatrix instanceof Matrix) {
+	      // submatrix size
+	      sSize = submatrix.size();
+	      // use array representation
+	      submatrix = submatrix.toArray();
+	    }
+	    else {
+	      // get submatrix size (array, scalar)
+	      sSize = array.size(submatrix);
+	    }
+	    
+	    // check index is a scalar
+	    if (isScalar) {
+	      // verify submatrix is a scalar
+	      if (sSize.length !== 0) {
+	        throw new TypeError('Scalar expected');
+	      }
+	      // set value
+	      matrix.set(index.min(), submatrix, defaultValue);
+	    }
+	    else {
+	      // validate dimensions, index size must be one or two dimensions
+	      if (iSize.length !== 1 && iSize.length !== 2) {
+	        throw new DimensionError(iSize.length, matrix._size.length, '<');
+	      }
+	      
+	      // check submatrix and index have the same dimensions
+	      if (sSize.length < iSize.length) {
+	        // calculate number of missing outer dimensions
+	        var i = 0;
+	        var outer = 0;
+	        while (iSize[i] === 1 && sSize[i] === 1) {
+	          i++;
+	        }
+	        while (iSize[i] === 1) {
+	          outer++;
+	          i++;
+	        }
+	        // unsqueeze both outer and inner dimensions
+	        submatrix = array.unsqueeze(submatrix, iSize.length, outer, sSize);
+	      }
+	      
+	      // check whether the size of the submatrix matches the index size
+	      if (!object.deepEqual(iSize, sSize)) {
+	        throw new DimensionError(iSize, sSize, '>');
+	      }
+	      
+	      // offsets
+	      var x0 = index.min()[0];
+	      var y0 = index.min()[1];      
+	      
+	      // submatrix rows and columns
+	      var m = sSize[0];
+	      var n = sSize[1];
+
+	      // loop submatrix
+	      for (var x = 0; x < m; x++) {
+	        // loop columns
+	        for (var y = 0; y < n; y++) {
+	          // value at i, j
+	          var v = submatrix[x][y];
+	          // invoke set (zero value will remove entry from matrix)
+	          matrix.set([x + x0, y + y0], v, defaultValue);
+	        }
+	      }
+	    }
+	    return matrix;
+	  };
+
+	  /**
+	   * Get a single element from the matrix.
+	   * @param {Number[]} index   Zero-based index
+	   * @return {*} value
+	   */
+	  CcsMatrix.prototype.get = function (index) {
+	    if (!isArray(index))
+	      throw new TypeError('Array expected');
+	    if (index.length != this._size.length)
+	      throw new DimensionError(index.length, this._size.length);
+
+	    // row and column
+	    var i = index[0];
+	    var j = index[1];
+
+	    // check i, j are valid
+	    validateIndex(i, this._size[0]);
+	    validateIndex(j, this._size[1]);
+
+	    // find value index
+	    var k = _getValueIndex(i, this._ptr[j], this._ptr[j + 1], this._index);
+	    // check k is prior to next column k and it is in the correct row
+	    if (k < this._ptr[j + 1] && this._index[k] === i)
+	      return object.clone(this._values[k]);
+
+	    return 0;
+	  };
+	  
+	  /**
+	   * Replace a single element in the matrix.
+	   * @param {Number[]} index   Zero-based index
+	   * @param {*} value
+	   * @param {*} [defaultValue]        Default value, filled in on new entries when
+	   *                                  the matrix is resized. If not provided,
+	   *                                  new matrix elements will be set to zero.
+	   * @return {CcsMatrix} self
+	   */
+	  CcsMatrix.prototype.set = function (index, v, defaultValue) {
+	    if (!isArray(index))
+	      throw new TypeError('Array expected');
+	    if (index.length != this._size.length)
+	      throw new DimensionError(index.length, this._size.length);
+
+	    // row and column
+	    var i = index[0];
+	    var j = index[1];
+
+	    // rows & columns
+	    var rows = this._size[0];
+	    var columns = this._size[1];
+
+	    // check we need to resize matrix
+	    if (i > rows - 1 || j > columns - 1) {
+	      // resize matrix
+	      _resize(this, Math.max(i + 1, rows), Math.max(j + 1, columns), defaultValue);
+	      // update rows & columns
+	      rows = this._size[0];
+	      columns = this._size[1];
+	    }
+
+	    // check i, j are valid
+	    validateIndex(i, rows);
+	    validateIndex(j, columns);
+
+	    // find value index
+	    var k = _getValueIndex(i, this._ptr[j], this._ptr[j + 1], this._index);
+	    // check k is prior to next column k and it is in the correct row
+	    if (k < this._ptr[j + 1] && this._index[k] === i) {
+	      // check value != 0
+	      if (!math.equal(v, 0)) {
+	        // update value
+	        this._values[k] = v;
+	      }
+	      else {
+	        // remove value from matrix
+	        _remove(k, j, this._values, this._index, this._ptr);
+	      }
+	    }
+	    else {
+	      // insert value @ (i, j)
+	      _insert(k, i, j, v, this._values, this._index, this._ptr);
+	    }
+
+	    return this;
+	  };
+	  
+	  var _getValueIndex = function(i, top, bottom, index) {
+	    // check row is on the bottom side
+	    if (bottom - top === 0 || i > index[bottom - 1])
+	      return bottom;
+	    // loop until we find row index
+	    while (top < bottom) {
+	      // point in the middle (fast integer division)
+	      var p = ~~((top + bottom) / 2);
+	      // row @ p
+	      var r = index[p];
+	      // check we have to look on the top side, bottom side or we found the row
+	      if (i < r)
+	        bottom = p;
+	      else if (i > r)
+	        top = p + 1;
+	      else
+	        return p;
+	    }
+	    return top;
+	  };
+
+	  var _remove = function (k, j, values, index, ptr) {
+	    // remove value @ k
+	    values.splice(k, 1);
+	    index.splice(k, 1);
+	    // update pointers
+	    for (var x = j + 1; x < ptr.length; x++)
+	      ptr[x]--;
+	  };
+
+	  var _insert = function (k, i, j, v, values, index, ptr) {
+	    // insert value
+	    values.splice(k, 0, v);
+	    // update row for k
+	    index.splice(k, 0, i);
+	    // update column pointers
+	    for (var x = j + 1; x < ptr.length; x++)
+	      ptr[x]++;
+	  };
+	  
+	  /**
+	   * Resize the matrix to the given size. Returns a copy of the matrix when 
+	   * `copy=true`, otherwise return the matrix itself (resize in place).
+	   *
+	   * @param {Number[]} size           The new size the matrix should have.
+	   * @param {*} [defaultValue=0]      Default value, filled in on new entries.
+	   *                                  If not provided, the matrix elements will
+	   *                                  be filled with zeros.
+	   * @param {boolean} [copy]          Return a resized copy of the matrix
+	   *
+	   * @return {Matrix}                 The resized matrix
+	   */
+	  CcsMatrix.prototype.resize = function (size, defaultValue, copy) {    
+	    // validate arguments
+	    if (!isArray(size))
+	      throw new TypeError('Array expected');
+	    if (size.length !== 2)
+	      throw new Error('Only two dimensions matrix are supported');
+
+	    // check sizes
+	    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) + ')');
+	      }
+	    });
+	    
+	    // matrix to resize
+	    var m = copy ? this.clone() : this;
+	    // resize matrix
+	    return _resize(m, size[0], size[1], defaultValue);
+	  };
+	  
+	  var _resize = function (matrix, rows, columns, defaultValue) {
+	    // value to insert at the time of growing matrix
+	    var value = defaultValue || 0;
+	    // should we insert the value?
+	    var ins = !math.equal(value, 0);
+
+	    // old columns and rows
+	    var r = matrix._size[0];
+	    var c = matrix._size[1];
+
+	    var i, j, k;
+
+	    // check we need to increase columns
+	    if (columns > c) {
+	      // loop new columns
+	      for (j = c; j < columns; j++) {
+	        // update matrix._ptr for current column
+	        matrix._ptr[j] = matrix._values.length;
+	        // check we need to insert matrix._values
+	        if (ins) {
+	          // loop rows
+	          for (i = 0; i < r; i++) {
+	            // add new matrix._values
+	            matrix._values.push(value);
+	            // update matrix._index
+	            matrix._index.push(i);
+	          }
+	        }        
+	      }
+	      // store number of matrix._values in matrix._ptr
+	      matrix._ptr[columns] = matrix._values.length;
+	    }
+	    else if (columns < c) {
+	      // truncate matrix._ptr
+	      matrix._ptr.splice(columns + 1, c - columns);
+	      // truncate matrix._values and matrix._index
+	      matrix._values.splice(matrix._ptr[columns], matrix._values.length);
+	      matrix._index.splice(matrix._ptr[columns], matrix._index.length);
+	    }
+	    // update columns
+	    c = columns;
+
+	    // check we need to increase rows
+	    if (rows > r) {
+	      // check we have to insert values
+	      if (ins) {
+	        // inserts
+	        var n = 0;
+	        // loop columns
+	        for (j = 0; j < c; j++) {
+	          // update matrix._ptr for current column
+	          matrix._ptr[j] = matrix._ptr[j] + n;
+	          // where to insert matrix._values
+	          k = matrix._ptr[j + 1] + n;
+	          // pointer
+	          var p = 0;
+	          // loop new rows, initialize pointer
+	          for (i = r; i < rows; i++, p++) {
+	            // add value
+	            matrix._values.splice(k + p, 0, value);
+	            // update matrix._index
+	            matrix._index.splice(k + p, 0, i);
+	            // increment inserts
+	            n++;
+	          }
+	        }
+	        // store number of matrix._values in matrix._ptr
+	        matrix._ptr[c] = matrix._values.length;
+	      }
+	    }
+	    else if (rows < r) {
+	      // deletes
+	      var d = 0;
+	      // loop columns
+	      for (j = 0; j < c; j++) {
+	        // update matrix._ptr for current column
+	        matrix._ptr[j] = matrix._ptr[j] - d;
+	        // where matrix._values start for next column
+	        var k0 = matrix._ptr[j];
+	        var k1 = matrix._ptr[j + 1] - d;
+	        // loop matrix._index
+	        for (k = k0; k < k1; k++) {
+	          // row
+	          i = matrix._index[k];
+	          // check we need to delete value and matrix._index
+	          if (i > rows - 1) {
+	            // remove value
+	            matrix._values.splice(k, 1);
+	            // remove item from matrix._index
+	            matrix._index.splice(k, 1);
+	            // increase deletes
+	            d++;
+	          }
+	        }
+	      }
+	      // update matrix._ptr for current column
+	      matrix._ptr[j] = matrix._values.length;
+	    }
+	    // update matrix._size
+	    matrix._size[0] = rows;
+	    matrix._size[1] = columns;
+	    // return matrix
+	    return matrix;
+	  };
+	  
+	  /**
+	   * Create a clone of the matrix
+	   * @return {CcsMatrix} clone
+	   */
+	  CcsMatrix.prototype.clone = function () {
+	    var m = new CcsMatrix({
+	      values: object.clone(this._values),
+	      index: object.clone(this._index),
+	      ptr: object.clone(this._ptr),
+	      size: object.clone(this._size)
+	    });
+	    return m;
+	  };
+	  
+	  /**
+	   * Retrieve the size of the matrix.
+	   * @returns {Number[]} size
+	   */
+	  CcsMatrix.prototype.size = function() {
+	    return object.clone(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 function is invoked with three
+	   *                              parameters: the value of the element, the index
+	   *                              of the element, and the Matrix being traversed.
+	   * @param {boolean} [skipZeros] Invoke callback function for non-zero values only.
+	   *
+	   * @return {CcsMatrix} matrix
+	   */
+	  CcsMatrix.prototype.map = function (callback, skipZeros) {
+	    // matrix instance
+	    var me = this;
+	    // rows and columns
+	    var rows = this._size[0];
+	    var columns = this._size[1];
+	    // invoke callback
+	    var invoke = function (v, i, j) {
+	      // invoke callback
+	      return callback(v, [i, j], me);
+	    };
+	    // invoke _map
+	    return _map(this, 0, rows - 1, 0, columns - 1, invoke, skipZeros);
+	  };
+
+	  /**
+	   * Create a new matrix with the results of the callback function executed on the interval
+	   * [minRow..maxRow, minColumn..maxColumn].
+	   */
+	  var _map = function (matrix, minRow, maxRow, minColumn, maxColumn, callback, skipZeros) {
+	    // result arrays
+	    var values = [];
+	    var index = [];
+	    var ptr = [];
+	    // invoke callback
+	    var invoke = function (v, x, y) {
+	      // invoke callback
+	      v = callback(v, x, y);
+	      // check value != 0
+	      if (!math.equal(v, 0)) {
+	        // store value
+	        values.push(v);
+	        // index
+	        index.push(x);
+	      }
+	    };
+	    // loop columns
+	    for (var j = minColumn; j <= maxColumn; j++) {
+	      // store pointer to values index
+	      ptr.push(values.length);
+	      // k0 <= k < k1 where k0 = _ptr[j] && k1 = _ptr[j+1]
+	      var k0 = matrix._ptr[j];
+	      var k1 = matrix._ptr[j + 1];
+	      // row pointer
+	      var p = minRow;
+	      // loop k within [k0, k1[
+	      for (var k = k0; k < k1; k++) {
+	        // row index
+	        var i = matrix._index[k];
+	        // check i is in range
+	        if (i >= minRow && i <= maxRow) {
+	          // zero values
+	          if (!skipZeros) {
+	           for (var x = p; x < i; x++)
+	             invoke(0, x - minRow, j - minColumn);
+	          }
+	          // value @ k
+	          invoke(matrix._values[k], i - minRow, j - minColumn);
+	        }
+	        // update pointer
+	        p = i + 1;
+	      }
+	      // zero values
+	      if (!skipZeros) {
+	        for (var y = p; y <= maxRow; y++)
+	          invoke(0, y - minRow, j - minColumn);
+	      }
+	    }
+	    // store number of values in ptr
+	    ptr.push(values.length);
+	    // return ccs
+	    return new CcsMatrix({
+	      values: values,
+	      index: index,
+	      ptr: ptr,
+	      size: [maxRow - minRow + 1, maxColumn - minColumn + 1]
+	    });
+	  };
+	  
+	  /**
+	   * Execute a callback function on each entry of the matrix.
+	   * @param {function} callback   The callback function is invoked with three
+	   *                              parameters: the value of the element, the index
+	   *                              of the element, and the Matrix being traversed.
+	   * @param {boolean} [skipZeros] Invoke callback function for non-zero values only.
+	   */
+	  CcsMatrix.prototype.forEach = function (callback, skipZeros) {
+	    // matrix instance
+	    var me = this;
+	    // rows and columns
+	    var rows = this._size[0];
+	    var columns = this._size[1];
+	    // loop columns
+	    for (var j = 0; j < columns; j++) {
+	      // k0 <= k < k1 where k0 = _ptr[j] && k1 = _ptr[j+1]
+	      var k0 = this._ptr[j];
+	      var k1 = this._ptr[j + 1];
+	      // column pointer
+	      var p = 0;
+	      // loop k within [k0, k1[
+	      for (var k = k0; k < k1; k++) {
+	        // row index
+	        var i = this._index[k];
+	        // check we need to process zeros
+	        if (!skipZeros) {
+	          // zero values
+	          for (var x = p; x < i; x++)
+	            callback(0, [x, j], me);
+	        }
+	        // value @ k
+	        callback(this._values[k], [i, j], me);
+	        // update pointer
+	        p = i + 1;
+	      }
+	      // check we need to process zeros
+	      if (!skipZeros) {
+	        // zero values
+	        for (var y = p; y < rows; y++)
+	          callback(0, [y, j], me);
+	      }
+	    }
+	  };
+	  
+	  /**
+	   * Create an Array with a copy of the data of the CcsMatrix
+	   * @returns {Array} array
+	   */
+	  CcsMatrix.prototype.toArray = function () {
+	    return _toArray(this, true);
+	  };
+
+	  /**
+	   * Get the primitive value of the CcsMatrix: a two dimensions array
+	   * @returns {Array} array
+	   */
+	  CcsMatrix.prototype.valueOf = function () {
+	    return _toArray(this, false);
+	  };
+	  
+	  var _toArray = function (matrix, copy) {
+	    // result
+	    var a = [];
+	    // rows and columns
+	    var rows = matrix._size[0];
+	    var columns = matrix._size[1];
+	    // loop columns
+	    for (var j = 0; j < columns; j++) {
+	      // k0 <= k < k1 where k0 = _ptr[j] && k1 = _ptr[j+1]
+	      var k0 = matrix._ptr[j];
+	      var k1 = matrix._ptr[j + 1];
+	      // row pointer
+	      var p = 0;
+	      // loop k within [k0, k1[
+	      for (var k = k0; k < k1; k++) {
+	        // row index
+	        var i = matrix._index[k];
+	        // zeros
+	        for (var x = p; x < i; x++)
+	          (a[x] = (a[x] || []))[j] = 0;
+	        // set value
+	        (a[i] = (a[i] || []))[j] = copy ? object.clone(matrix._values[k]) : matrix._values[k];
+	        // update pointer
+	        p = i + 1;
+	      }
+	      // zero values
+	      for (var y = p; y < rows; y++)
+	        (a[y] = (a[y] || []))[j] = 0;
+	    }
+	    return a;
+	  };
+	  
+	  /**
+	   * Get a string representation of the matrix, with optional formatting options.
+	   * @param {Object | Number | Function} [options]  Formatting options. See
+	   *                                                lib/util/number:format for a
+	   *                                                description of the available
+	   *                                                options.
+	   * @returns {String} str
+	   */
+	  CcsMatrix.prototype.format = function (options) {
+	    // rows and columns
+	    var rows = this._size[0];
+	    var columns = this._size[1];
+	    // rows & columns
+	    var str = 'CCS [' + string.format(rows, options) + ' x ' + string.format(columns, options) + '] density: ' + string.format(this._values.length / (rows * columns), options) + '\n';
+	    // loop columns
+	    for (var j = 0; j < columns; j++) {
+	      // k0 <= k < k1 where k0 = _ptr[j] && k1 = _ptr[j+1]
+	      var k0 = this._ptr[j];
+	      var k1 = this._ptr[j + 1];
+	      // loop k within [k0, k1[
+	      for (var k = k0; k < k1; k++) {
+	        // row index
+	        var i = this._index[k];
+	        // append value
+	        str += '\n    (' + string.format(i, options) + ', ' + string.format(j, options) + ') ==> ' + string.format(this._values[k], options);
+	      }
+	    }
+	    return str;
+	  };
+	  
+	  /**
+	   * Get a string representation of the matrix
+	   * @returns {String} str
+	   */
+	  CcsMatrix.prototype.toString = function () {
+	    return string.format(this.toArray());
+	  };
+	  
+	  /**
+	   * Get a JSON representation of the matrix
+	   * @returns {Object}
+	   */
+	  CcsMatrix.prototype.toJSON = function () {
+	    return {
+	      mathjs: 'CcsMatrix',
+	      values: this._values,
+	      index: this._index,
+	      ptr: this._ptr,
+	      size: this._size
+	    };
+	  };
+
+	  /**
+	   * Calculates the transpose of the matrix
+	   * @returns {Matrix}
+	   */
+	  CcsMatrix.prototype.transpose = function () {
+	    // rows and columns
+	    var rows = this._size[0];
+	    var columns = this._size[1];
+	    // check columns
+	    if (columns === 0) {
+	      // throw exception
+	      throw new RangeError('Cannot transpose a 2D matrix with no columns (size: ' + string.format(this._size) + ')');
+	    }
+	    // ccs transpose is a crs matrix with the same structure
+	    return new math.type.CrsMatrix({
+	      values: object.clone(this._values),
+	      index: object.clone(this._index),
+	      ptr: object.clone(this._ptr),
+	      size: [columns, rows]
+	    });
+	  };
+
+	  /**
+	   * Get the kth Matrix diagonal.
+	   *
+	   * @param {Number | BigNumber} [k=0]     The kth diagonal where the vector will retrieved.
+	   *
+	   * @returns {Array}                      The array vector with the diagonal values.
+	   */
+	  CcsMatrix.prototype.diagonal = function(k) {
+	    // validate k if any
+	    if (k) {
+	      // convert BigNumber to a number
+	      if (k instanceof BigNumber) 
+	        k = k.toNumber();
+	      // is must be an integer
+	      if (!isNumber(k) || !isInteger(k)) {
+	        throw new TypeError ('The parameter k must be an integer number');
+	      }
+	    }
+	    else {
+	      // default value
+	      k = 0;
+	    }
+
+	    var kSuper = k > 0 ? k : 0;
+	    var kSub = k < 0 ? -k : 0;
+	    
+	    // rows & columns
+	    var rows = this._size[0];
+	    var columns = this._size[1];
+	    
+	    // number diagonal values
+	    var n = Math.min(rows - kSub, columns -  kSuper);
+	    
+	    // diagonal
+	    var values = [];
+	    // loop columns
+	    for (var j = kSuper; j < columns && values.length < n; j++) {
+	      // k0 <= k < k1 where k0 = _ptr[j] && k1 = _ptr[j+1]
+	      var k0 = this._ptr[j];
+	      var k1 = this._ptr[j + 1];
+	      // column value flag
+	      var cv = false;
+	      // loop x within [k0, k1[
+	      for (var x = k0; x < k1; x++) {
+	        // row index
+	        var i = this._index[x];
+	        // check row
+	        if (i === j - kSuper + kSub) {
+	          // set flag
+	          cv = true;
+	          // value on this column
+	          values.push(object.clone(this._values[x]));
+	          // exit loop
+	          break;
+	        }
+	        else if (i > j - kSuper + kSub) {
+	          // exit loop, no value on the diagonal for column j
+	          break;
+	        }
+	      }
+	      // check this column has a value set
+	      if (!cv && values.length < n) {
+	        // zero on this column
+	        values.push(0);
+	      }
+	    }
+	    return values;
+	  };
+	  
+	  /**
+	   * Generate a matrix from a JSON object
+	   * @param {Object} json  An object structured like
+	   *                       `{"mathjs": "CcsMatrix", "values": [], "index": [], "ptr": [], "size": []}`,
+	   *                       where mathjs is optional
+	   * @returns {CcsMatrix}
+	   */
+	  CcsMatrix.fromJSON = function (json) {
+	    return new CcsMatrix(json);
+	  };
+
+	  /**
+	   * Create a diagonal matrix.
+	   *
+	   * @param {Array} size                   The matrix size.
+	   * @param {Number, Array} value          The values for the diagonal.
+	   * @param {Number | BigNumber} [k=0]     The kth diagonal where the vector will be filled in.
+	   *
+	   * @returns {CcsMatrix}
+	   */
+	  CcsMatrix.diagonal = function (size, value, k) {
+	    if (!isArray(size))
+	      throw new TypeError('Array expected, size parameter');
+	    if (size.length !== 2)
+	      throw new Error('Only two dimensions matrix are supported');
+	    
+	    // map size & validate
+	    size = size.map(function (s) {
+	      // check it is a big number
+	      if (s instanceof BigNumber) {
+	        // convert it
+	        s = s.toNumber();
+	      }
+	      // validate arguments
+	      if (!isNumber(s) || !isInteger(s) || s < 1) {
+	        throw new Error('Size values must be positive integers');
+	      } 
+	      return s;
+	    });
+	    
+	    // validate k if any
+	    if (k) {
+	      // convert BigNumber to a number
+	      if (k instanceof BigNumber) 
+	        k = k.toNumber();
+	      // is must be an integer
+	      if (!isNumber(k) || !isInteger(k)) {
+	        throw new TypeError ('The parameter k must be an integer number');
+	      }
+	    }
+	    else {
+	      // default value
+	      k = 0;
+	    }
+
+	    var kSuper = k > 0 ? k : 0;
+	    var kSub = k < 0 ? -k : 0;
+	    
+	    // rows and columns
+	    var rows = size[0];
+	    var columns = size[1];
+	    
+	    // number of non-zero items
+	    var n = Math.min(rows - kSub, columns -  kSuper);
+	    
+	    // value extraction function
+	    var _value;
+	      
+	    // check value
+	    if (isArray(value)) {
+	      // validate array
+	      if (value.length !== n) {
+	        // number of values in array must be n
+	        throw new Error('Invalid value array length');
+	      }
+	      // define function
+	      _value = function (i) {
+	        // return value @ i
+	        return value[i];
+	      };
+	    }
+	    else {
+	      // define function
+	      _value = function () {
+	        // return value
+	        return value;
+	      };
+	    }
+	    
+	    // create arrays
+	    var values = [];
+	    var index = [];
+	    var ptr = [];
+	    
+	    // loop items
+	    for (var j = 0; j < columns; j++) {
+	      // number of rows with value
+	      ptr.push(values.length);
+	      // diagonal index
+	      var i = j - kSuper;      
+	      // check we need to set diagonal value
+	      if (i >= 0 && i < n) {
+	        // get value @ i
+	        var v = _value(i);
+	        // check for zero
+	        if (!math.equal(v, 0)) {
+	          // column
+	          index.push(i + kSub);
+	          // add value
+	          values.push(v);
+	        }
+	      }
+	    }
+	    // last value should be number of values
+	    ptr.push(values.length);
+	    // create CcsMatrix
+	    return new CcsMatrix({
+	      values: values,
+	      index: index,
+	      ptr: ptr,
+	      size: [rows, columns]
+	    });
+	  };
+	  
+	  /**
+	   * Calculate the trace of a matrix: the sum of the elements on the main
+	   * diagonal of a square matrix.
+	   *
+	   * See also:
+	   *
+	   *    diagonal
+	   *
+	   * @returns {Number}       The matrix trace
+	   */
+	  CcsMatrix.prototype.trace = function () {
+	    // size
+	    var size = this._size;
+	    // check dimensions
+	    var rows = size[0];
+	    var columns = size[1];
+	    // matrix must be square
+	    if (rows === columns) {
+	      // calulate sum
+	      var sum = 0;
+	      // check we have data (avoid looping columns)
+	      if (this._values.length > 0) {
+	        // loop columns
+	        for (var j = 0; j < columns; j++) {
+	          // k0 <= k < k1 where k0 = _ptr[j] && k1 = _ptr[j+1]
+	          var k0 = this._ptr[j];
+	          var k1 = this._ptr[j + 1];
+	          // loop k within [k0, k1[
+	          for (var k = k0; k < k1; k++) {
+	            // row index
+	            var i = this._index[k];
+	            // check row
+	            if (i === j) {
+	              // accumulate value
+	              sum = math.add(sum, this._values[k]);
+	              // exit loop
+	              break;
+	            }
+	            if (i > j) {
+	              // exit loop, no value on the diagonal for column j
+	              break;
+	            }
+	          }
+	        }
+	      }
+	      // return trace
+	      return sum;
+	    }
+	    throw new RangeError('Matrix must be square (size: ' + string.format(size) + ')');        
+	  };
+	  
+	  /**
+	   * Multiply the matrix values times the argument.
+	   *
+	   * @param  {Number | BigNumber | Boolean | Complex | Unit | Array | Matrix | null} Value to multiply.
+	   *
+	   * @return {Number | BigNumber | Complex | Unit | Matrix}
+	   */
+	  CcsMatrix.prototype.multiply = function (value) {
+	    // check dimensions
+	    var rows = this._size[0];
+	    var columns = this._size[1];
+	    
+	    // check value is a matrix
+	    if (value instanceof Matrix) {
+	      // matrix size
+	      var z = value.size();
+	      // check value is a vector
+	      if (z.length === 1) {
+	        // mutiply matrix x vector array
+	        return _multiply(this, z[0], 1, function (i) {
+	          // value[i]
+	          return value.get([i]);
+	        });
+	      }
+	      // check two dimensions matrix
+	      if (z.length === 2) {        
+	        // mutiply matrix x matrix
+	        return _multiply(this, z[0], z[1], function (i, j) {
+	          // value[i, j]
+	          return value.get([i, j]);
+	        });
+	      }
+	      throw new Error('Can only multiply a 1 or 2 dimensional matrix ' +
+	                      '(value has ' + z.length + ' dimensions)');
+	    }
+
+	    // check value is an array
+	    if (isArray(value)) {
+	      // array size
+	      var s = array.size(value);
+	      // check value is a vector
+	      if (s.length === 1) {
+	        // mutiply matrix x vector array
+	        return _multiply(this, s[0], 1, function (i) {
+	          // value[i]
+	          return value[i];
+	        });
+	      }
+	      if (s.length === 2) {
+	        // mutiply matrix x array
+	        return _multiply(this, s[0], s[1], function (i, j) {
+	          // value[i, j]
+	          return value[i][j];
+	        });
+	      }
+	      throw new Error('Can only multiply a 1 or 2 dimensional matrix ' +
+	                      '(value has ' + s.length + ' dimensions)');
+	    }
+	    
+	    var callback = function (v) {
+	      return math.multiply(v, value);
+	    };
+
+	    // map non zero elements
+	    return _map(this, 0, rows - 1, 0, columns - 1, callback, false);
+	  };
+
+	  var _multiply = function (matrix, r, c, get) {
+	  
+	    // matrix dimensions
+	    var rows = matrix._size[0];
+	    var columns = matrix._size[1];
+	    
+	    // check dimensions match
+	    if (columns !== r) {
+	      // throw error
+	      throw new RangeError('Dimension mismatch in multiplication. ' +
+	                           'Columns of A must match length of B ' +
+	                           '(A is ' + rows + 'x' + columns +
+	                           ', B is ' + r + ', ' +
+	                           columns + ' != ' + r + ')');
+	    }
+	    
+	    // result arrays
+	    var values = [];
+	    var index = [];
+	    var ptr = [];
+
+	    // create array with rows entries
+	    var data = [];
+	    for (var x = 0; x < rows; x++)
+	      data[x] = 0;
+	    // loop value columns
+	    for (var z = 0; z < c; z++) {
+	      // update ptr
+	      ptr.push(values.length);
+	      // do not traverse rows in matrix, it is not efficient in CCS
+	      for (var j = 0; j < columns; j++) {          
+	        // k0 <= k < k1 where k0 = _ptr[j] && k1 = _ptr[j+1]
+	        var k0 = matrix._ptr[j];
+	        var k1 = matrix._ptr[j + 1];
+	        // loop k within [k0, k1[
+	        for (var k = k0; k < k1; k++) {
+	          // row
+	          var i = matrix._index[k];
+	          // multiply & aggregate
+	          data[i] = math.add(data[i], math.multiply(matrix._values[k], get(j, z)));
+	        }          
+	      }
+	      // finished processing column z, compress results
+	      for (var y = 0; y < rows; y++) {
+	        // check value is different than zero
+	        if (!math.equal(data[y], 0)) {
+	          // push value
+	          values.push(data[y]);
+	          index.push(y);          
+	        }
+	        // reset value
+	        data[y] = 0;
+	      }
+	    }
+	    // update ptr
+	    ptr.push(values.length);
+	    
+	    // check we need to squeeze the result into a scalar
+	    if (rows === 1 && c === 1)
+	      return values.length === 1 ? values[0] : 0;
+	    
+	    // return CCS matrix
+	    return new CcsMatrix({
+	      values: values,
+	      index: index,
+	      ptr: ptr,
+	      size: [rows, c]
+	    });
+	  };
+	  
+	  return CcsMatrix;
+	};
 
 /***/ },
 /* 16 */
@@ -4077,1769 +5114,4033 @@
 
 	'use strict';
 
-	var util = __webpack_require__(171),
-
-	    ArgumentsError = __webpack_require__(167),
+	var util = __webpack_require__(174);
+	var DimensionError = __webpack_require__(171);
+
+	var array = util.array;
+	var object = util.object;
+	var string = util.string;
+	var number = util.number;
+
+	var isArray = Array.isArray;
+	var isNumber = util.number.isNumber;
+	var isInteger = util.number.isInteger;
+
+	var validateIndex = array.validateIndex;
+
+	module.exports = function (math) {
+
+	  var Index = math.type.Index,
+	      BigNumber = math.type.BigNumber,
+	      Matrix = math.type.Matrix;
+
+	  function CrsMatrix(data) {
+	    if (!(this instanceof CrsMatrix))
+	      throw new SyntaxError('Constructor must be called with the new operator');
+
+	    if (data instanceof Matrix) {
+	      // check data is a CrsMatrix
+	      if (data.type === 'CrsMatrix') {
+	        // clone arrays
+	        this._values = object.clone(data._values);
+	        this._index = object.clone(data._index);
+	        this._ptr = object.clone(data._ptr);
+	        this._size = object.clone(data._size);
+	      }
+	      else {
+	        // build from matrix data
+	        _createFromArray(this, data.valueOf());
+	      }
+	    }
+	    else if (data && isArray(data.values) && isArray(data.index) && isArray(data.ptr) && isArray(data.size)) {
+	      // initialize fields
+	      this._values = data.values;
+	      this._index = data.index;
+	      this._ptr = data.ptr;
+	      this._size = data.size;
+	    }
+	    else if (isArray(data)) {
+	      // create from array
+	      _createFromArray(this, data);
+	    }
+	    else if (data) {
+	      // unsupported type
+	      throw new TypeError('Unsupported type of data (' + util.types.type(data) + ')');
+	    }
+	    else {
+	      // nothing provided
+	      this._values = [];
+	      this._index = [];
+	      this._ptr = [0];
+	      this._size = [0];
+	    }
+	  }
+
+	  var _createFromArray = function (matrix, data) {
+	    // initialize fields
+	    matrix._values = [];
+	    matrix._index = [];
+	    matrix._ptr = [];
+	    // discover rows & columns, do not use math.size() to avoid looping array twice
+	    var rows = data.length;
+	    var columns = 0;
+
+	    // loop rows
+	    for (var i = 0; i < rows; i++) {
+	      // store value index in ptr
+	      matrix._ptr.push(matrix._values.length);
+	      // current row
+	      var row = data[i];      
+	      // check row is an array
+	      if (isArray(row)) {
+	        // update columns if needed
+	        if (row.length > columns)
+	          columns = row.length;
+	        // loop columns
+	        for (var j = 0; j < row.length; j++) {
+	          // value at data[i][j]
+	          var v = row[j];
+	          // check value != 0
+	          if (!math.equal(v, 0)) {
+	            // store value
+	            matrix._values.push(v);
+	            // add column index
+	            matrix._index.push(j);
+	          }
+	        }
+	      }
+	      else {
+	        // update columns if needed (only on first row)
+	        if (i === 0 && columns < 1)
+	          columns = 1;
+	        // check value != 0 (row is a scalar)
+	        if (!math.equal(row, 0)) {
+	          // store value
+	          matrix._values.push(row);
+	          // index
+	          matrix._index.push(0);
+	        }
+	      }
+	    }
+	    // store number of values in ptr
+	    matrix._ptr.push(matrix._values.length);
+	    // size
+	    matrix._size = [rows, columns];
+	  };
+
+	  CrsMatrix.prototype = new math.type.Matrix();
+
+	  CrsMatrix.prototype.type = 'CrsMatrix';
+
+	  /**
+	   * Get the storage format used by the matrix.
+	   *
+	   * Usage:
+	   *     var format = matrix.storage()                   // retrieve storage format
+	   *
+	   * @return {string}           The storage format.
+	   */
+	  CrsMatrix.prototype.storage = function () {
+	    return 'crs';
+	  };
+
+	  /**
+	   * Get a subset of the matrix, or replace a subset of the matrix.
+	   *
+	   * Usage:
+	   *     var subset = matrix.subset(index)               // retrieve subset
+	   *     var value = matrix.subset(index, replacement)   // replace subset
+	   *
+	   * @param {Index} index
+	   * @param {Array | Maytrix | *} [replacement]
+	   * @param {*} [defaultValue=0]      Default value, filled in on new entries when
+	   *                                  the matrix is resized. If not provided,
+	   *                                  new matrix elements will be filled with zeros.
+	   */
+	  CrsMatrix.prototype.subset = function (index, replacement, defaultValue) {
+	    // check arguments
+	    switch (arguments.length) {
+	      case 1:
+	        return _getsubset(this, index);
+
+	        // intentional fall through
+	      case 2:
+	      case 3:
+	        return _setsubset(this, index, replacement, defaultValue);
+
+	      default:
+	        throw new SyntaxError('Wrong number of arguments');
+	    }
+	  };
+
+	  var _getsubset = function (matrix, index) {
+	    // check index
+	    if (!(index instanceof Index)) {
+	      throw new TypeError('Invalid index');
+	    }
+
+	    var isScalar = index.isScalar();
+	    if (isScalar) {
+	      // return a scalar
+	      return matrix.get(index.min());
+	    }
+	    // validate dimensions
+	    var size = index.size();
+	    if (size.length != matrix._size.length) {
+	      throw new DimensionError(size.length, matrix._size.length);
+	    }
+
+	    // validate if any of the ranges in the index is out of range
+	    var min = index.min();
+	    var max = index.max();
+	    for (var i = 0, ii = matrix._size.length; i < ii; i++) {
+	      validateIndex(min[i], matrix._size[i]);
+	      validateIndex(max[i], matrix._size[i]);
+	    }
+
+	    // map callback
+	    var callback = function (v) {
+	      // return value
+	      return v;
+	    };
+	    // get sub-matrix
+	    return _map(matrix, min[0], max[0], min[1], max[1], callback, false);
+	  };
+
+	  var _setsubset = function (matrix, index, submatrix, defaultValue) {
+	    // check index
+	    if (!(index instanceof Index)) {
+	      throw new TypeError('Invalid index');
+	    }
+
+	    // get index size and check whether the index contains a single value
+	    var iSize = index.size(),
+	        isScalar = index.isScalar();
+
+	    // calculate the size of the submatrix, and convert it into an Array if needed
+	    var sSize;
+	    if (submatrix instanceof Matrix) {
+	      // submatrix size
+	      sSize = submatrix.size();
+	      // use array representation
+	      submatrix = submatrix.toArray();
+	    }
+	    else {
+	      // get submatrix size (array, scalar)
+	      sSize = array.size(submatrix);
+	    }
+
+	    // check index is a scalar
+	    if (isScalar) {
+	      // verify submatrix is a scalar
+	      if (sSize.length !== 0) {
+	        throw new TypeError('Scalar expected');
+	      }
+	      // set value
+	      matrix.set(index.min(), submatrix, defaultValue);
+	    }
+	    else {
+	      // validate dimensions, index size must be one or two dimensions
+	      if (iSize.length !== 1 && iSize.length !== 2) {
+	        throw new DimensionError(iSize.length, matrix._size.length, '<');
+	      }
+
+	      // check submatrix and index have the same dimensions
+	      if (sSize.length < iSize.length) {
+	        // calculate number of missing outer dimensions
+	        var i = 0;
+	        var outer = 0;
+	        while (iSize[i] === 1 && sSize[i] === 1) {
+	          i++;
+	        }
+	        while (iSize[i] === 1) {
+	          outer++;
+	          i++;
+	        }
+	        // unsqueeze both outer and inner dimensions
+	        submatrix = array.unsqueeze(submatrix, iSize.length, outer, sSize);
+	      }
+
+	      // check whether the size of the submatrix matches the index size
+	      if (!object.deepEqual(iSize, sSize)) {
+	        throw new DimensionError(iSize, sSize, '>');
+	      }
+
+	      // offsets
+	      var x0 = index.min()[0];
+	      var y0 = index.min()[1];      
+
+	      // submatrix rows and columns
+	      var m = sSize[0];
+	      var n = sSize[1];
+
+	      // loop submatrix
+	      for (var x = 0; x < m; x++) {
+	        // loop columns
+	        for (var y = 0; y < n; y++) {
+	          // value at i, j
+	          var v = submatrix[x][y];
+	          // invoke set (zero value will remove entry from matrix)
+	          matrix.set([x + x0, y + y0], v, defaultValue);
+	        }
+	      }
+	    }
+	    return matrix;
+	  };
+
+	  /**
+	   * Get a single element from the matrix.
+	   * @param {Number[]} index   Zero-based index
+	   * @return {*} value
+	   */
+	  CrsMatrix.prototype.get = function (index) {
+	    if (!isArray(index))
+	      throw new TypeError('Array expected');
+	    if (index.length != this._size.length)
+	      throw new DimensionError(index.length, this._size.length);
+
+	    // row and column
+	    var i = index[0];
+	    var j = index[1];
+
+	    // check i, j are valid
+	    validateIndex(i, this._size[0]);
+	    validateIndex(j, this._size[1]);
+
+	    // find value index
+	    var k = _getValueIndex(j, this._ptr[i], this._ptr[i + 1], this._index);
+	    // check k is prior to next row k and it is in the correct row
+	    if (k < this._ptr[i + 1] && this._index[k] === j)
+	      return object.clone(this._values[k]);
+
+	    return 0;
+	  };
+
+	  /**
+	   * Replace a single element in the matrix.
+	   * @param {Number[]} index   Zero-based index
+	   * @param {*} value
+	   * @param {*} [defaultValue]        Default value, filled in on new entries when
+	   *                                  the matrix is resized. If not provided,
+	   *                                  new matrix elements will be set to zero.
+	   * @return {CrsMatrix} self
+	   */
+	  CrsMatrix.prototype.set = function (index, v, defaultValue) {
+	    if (!isArray(index))
+	      throw new TypeError('Array expected');
+	    if (index.length != this._size.length)
+	      throw new DimensionError(index.length, this._size.length);
+
+	    // row and column
+	    var i = index[0];
+	    var j = index[1];
+
+	    // rows & columns
+	    var rows = this._size[0];
+	    var columns = this._size[1];
+
+	    // check we need to resize matrix
+	    if (i > rows - 1 || j > columns - 1) {
+	      // resize matrix
+	      _resize(this, Math.max(i + 1, rows), Math.max(j + 1, columns), defaultValue);
+	      // update rows & columns
+	      rows = this._size[0];
+	      columns = this._size[1];
+	    }
+
+	    // check i, j are valid
+	    validateIndex(i, rows);
+	    validateIndex(j, columns);
+
+	    // find value index
+	    var k = _getValueIndex(j, this._ptr[i], this._ptr[i + 1], this._index);
+	    // check k is prior to next row k and it is in the correct column
+	    if (k < this._ptr[i + 1] && this._index[k] === j) {
+	      // check value != 0
+	      if (!math.equal(v, 0)) {
+	        // update value
+	        this._values[k] = v;
+	      }
+	      else {
+	        // remove value from matrix
+	        _remove(k, i, this._values, this._index, this._ptr);
+	      }
+	    }
+	    else {
+	      // insert value @ (i, j)
+	      _insert(k, i, j, v, this._values, this._index, this._ptr);
+	    }
+
+	    return this;
+	  };
+
+	  var _getValueIndex = function(j, left, right, index) {
+	    // check column is on the right side
+	    if (right - left === 0 || j > index[right - 1])
+	      return right;
+	    // loop until we find row index
+	    while (left < right) {
+	      // point in the middle (fast integer division)
+	      var p = ~~((left + right) / 2);
+	      // column @ p
+	      var c = index[p];
+	      // check we have to look on the left side, right side or we found the column
+	      if (j < c)
+	        right = p;
+	      else if (j > c)
+	        left = p + 1;
+	      else
+	        return p;
+	    }
+	    return left;
+	  };
+
+	  var _remove = function (k, i, values, index, ptr) {
+	    // remove value @ k
+	    values.splice(k, 1);
+	    index.splice(k, 1);
+	    // update pointers
+	    for (var x = i + 1; x < ptr.length; x++)
+	      ptr[x]--;
+	  };
+
+	  var _insert = function (k, i, j, v, values, index, ptr) {
+	    // insert value
+	    values.splice(k, 0, v);
+	    // update column for k
+	    index.splice(k, 0, j);
+	    // update row pointers
+	    for (var x = i + 1; x < ptr.length; x++)
+	      ptr[x]++;
+	  };
+
+	  /**
+	   * Resize the matrix to the given size. Returns a copy of the matrix when 
+	   * `copy=true`, otherwise return the matrix itself (resize in place).
+	   *
+	   * @param {Number[]} size           The new size the matrix should have.
+	   * @param {*} [defaultValue=0]      Default value, filled in on new entries.
+	   *                                  If not provided, the matrix elements will
+	   *                                  be filled with zeros.
+	   * @param {boolean} [copy]          Return a resized copy of the matrix
+	   *
+	   * @return {Matrix}                 The resized matrix
+	   */
+	  CrsMatrix.prototype.resize = function (size, defaultValue, copy) {    
+	    // validate arguments
+	    if (!isArray(size))
+	      throw new TypeError('Array expected');
+	    if (size.length !== 2)
+	      throw new Error('Only two dimensions matrix are supported');
+
+	    // check sizes
+	    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) + ')');
+	      }
+	    });
+
+	    // matrix to resize
+	    var m = copy ? this.clone() : this;
+	    // resize matrix
+	    return _resize(m, size[0], size[1], defaultValue);
+	  };
+
+	  var _resize = function (matrix, rows, columns, defaultValue) {
+	    // value to insert at the time of growing matrix
+	    var value = defaultValue || 0;
+	    // should we insert the value?
+	    var ins = !math.equal(value, 0);
+
+	    // old columns and rows
+	    var r = matrix._size[0];
+	    var c = matrix._size[1];
+
+	    var i, j, k;
+
+	    // check we need to increase rows
+	    if (rows > r) {
+	      // loop new rows
+	      for (i = r; i < rows; i++) {
+	        // update matrix._ptr for current column
+	        matrix._ptr[i] = matrix._values.length;
+	        // check we need to insert matrix._values
+	        if (ins) {
+	          // loop columns
+	          for (j = 0; j < c; j++) {
+	            // add new matrix._values
+	            matrix._values.push(value);
+	            // update matrix._index
+	            matrix._index.push(j);
+	          }
+	        }        
+	      }
+	      // store number of matrix._values in matrix._ptr
+	      matrix._ptr[rows] = matrix._values.length;
+	    }
+	    else if (rows < r) {
+	      // truncate matrix._ptr
+	      matrix._ptr.splice(rows + 1, r - rows);
+	      // truncate matrix._values and matrix._index
+	      matrix._values.splice(matrix._ptr[rows], matrix._values.length);
+	      matrix._index.splice(matrix._ptr[rows], matrix._index.length);
+	    }
+	    // update rows
+	    r = rows;
+
+	    // check we need to increase columns
+	    if (columns > c) {
+	      // check we have to insert values
+	      if (ins) {
+	        // inserts
+	        var n = 0;
+	        // loop rows
+	        for (i = 0; i < r; i++) {
+	          // update matrix._ptr for current row
+	          matrix._ptr[i] = matrix._ptr[i] + n;
+	          // where to insert matrix._values
+	          k = matrix._ptr[i + 1] + n;
+	          // pointer
+	          var p = 0;
+	          // loop new columns, initialize pointer
+	          for (j = c; j < columns; j++, p++) {
+	            // add value
+	            matrix._values.splice(k + p, 0, value);
+	            // update matrix._index
+	            matrix._index.splice(k + p, 0, j);
+	            // increment inserts
+	            n++;
+	          }
+	        }
+	        // store number of matrix._values in matrix._ptr
+	        matrix._ptr[r] = matrix._values.length;
+	      }
+	    }
+	    else if (columns < c) {
+	      // deletes
+	      var d = 0;
+	      // loop rows
+	      for (i = 0; i < r; i++) {
+	        // update matrix._ptr for current row
+	        matrix._ptr[i] = matrix._ptr[i] - d;
+	        // where matrix._values start for next column
+	        var k0 = matrix._ptr[i];
+	        var k1 = matrix._ptr[i + 1] - d;
+	        // loop matrix._index
+	        for (k = k0; k < k1; k++) {
+	          // column
+	          j = matrix._index[k];
+	          // check we need to delete value and matrix._index
+	          if (j > columns - 1) {
+	            // remove value
+	            matrix._values.splice(k, 1);
+	            // remove item from matrix._index
+	            matrix._index.splice(k, 1);
+	            // increase deletes
+	            d++;
+	          }
+	        }
+	      }
+	      // update matrix._ptr for current column
+	      matrix._ptr[i] = matrix._values.length;
+	    }
+	    // update matrix._size
+	    matrix._size[0] = rows;
+	    matrix._size[1] = columns;
+	    // return matrix
+	    return matrix;
+	  };
+
+	  /**
+	   * Create a clone of the matrix
+	   * @return {CrsMatrix} clone
+	   */
+	  CrsMatrix.prototype.clone = function () {
+	    var m = new CrsMatrix({
+	      values: object.clone(this._values),
+	      index: object.clone(this._index),
+	      ptr: object.clone(this._ptr),
+	      size: object.clone(this._size)
+	    });
+	    return m;
+	  };
+
+	  /**
+	   * Retrieve the size of the matrix.
+	   * @returns {Number[]} size
+	   */
+	  CrsMatrix.prototype.size = function() {
+	    return object.clone(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 function is invoked with three
+	   *                              parameters: the value of the element, the index
+	   *                              of the element, and the Matrix being traversed.
+	   * @param {boolean} [skipZeros] Invoke callback function for non-zero values only.
+	   *
+	   * @return {Matrix} matrix
+	   */
+	  CrsMatrix.prototype.map = function (callback, skipZeros) {
+	    // matrix instance
+	    var me = this;
+	    // rows and columns
+	    var rows = this._size[0];
+	    var columns = this._size[1];
+	    // invoke callback
+	    var invoke = function (v, i, j) {
+	      // invoke callback
+	      return callback(v, [i, j], me);
+	    };
+	    // invoke _map
+	    return _map(this, 0, rows - 1, 0, columns - 1, invoke, skipZeros);
+	  };
+
+	  /**
+	   * Create a new matrix with the results of the callback function executed on the interval
+	   * [minRow..maxRow, minColumn..maxColumn].
+	   */
+	  var _map = function (matrix, minRow, maxRow, minColumn, maxColumn, callback, skipZeros) {
+	    // result arrays
+	    var values = [];
+	    var index = [];
+	    var ptr = [];
+	    // invoke callback
+	    var invoke = function (v, x, y) {
+	      // invoke callback
+	      v = callback(v, x, y);
+	      // check value != 0
+	      if (!math.equal(v, 0)) {
+	        // store value
+	        values.push(v);
+	        // index
+	        index.push(y);
+	      }
+	    };
+	    // loop rows
+	    for (var i = minRow; i <= maxRow; i++) {
+	      // store pointer to values index
+	      ptr.push(values.length);
+	      // k0 <= k < k1 where k0 = _ptr[j] && k1 = _ptr[j+1]
+	      var k0 = matrix._ptr[i];
+	      var k1 = matrix._ptr[i + 1];
+	      // column pointer
+	      var p = minColumn;
+	      // loop k within [k0, k1[
+	      for (var k = k0; k < k1; k++) {
+	        // column index
+	        var j = matrix._index[k];
+	        // check j is in range
+	        if (j >= minColumn && j <= maxColumn) {
+	          // zero values
+	          if (!skipZeros) {
+	            // write zeros from column p to j
+	            for (var x = p; x < j; x++)
+	              invoke(0, i - minRow, x - minColumn);
+	          }
+	          // value @ k
+	          invoke(matrix._values[k], i - minRow, j - minColumn);
+	        }
+	        // update pointer
+	        p = j + 1;
+	      }
+	      // zero values
+	      if (!skipZeros) {
+	        // write zeros from column p to maxColumn
+	        for (var y = p; y <= maxColumn; y++)
+	          invoke(0, i - minRow, y - minColumn);
+	      }
+	    }
+	    // store number of values in ptr
+	    ptr.push(values.length);
+	    // return ccs
+	    return new CrsMatrix({
+	      values: values,
+	      index: index,
+	      ptr: ptr,
+	      size: [maxRow - minRow + 1, maxColumn - minColumn + 1]
+	    });
+	  };
+
+	  /**
+	   * Execute a callback function on each entry of the matrix.
+	   * @param {function} callback   The callback function is invoked with three
+	   *                              parameters: the value of the element, the index
+	   *                              of the element, and the Matrix being traversed.
+	   * @param {boolean} [skipZeros] Invoke callback function for non-zero values only.
+	   */
+	  CrsMatrix.prototype.forEach = function (callback, skipZeros) {
+	    // matrix instance
+	    var me = this;
+	    // rows and columns
+	    var rows = this._size[0];
+	    var columns = this._size[1];
+	    // loop rows
+	    for (var i = 0; i < rows; i++) {
+	      // k0 <= k < k1 where k0 = _ptr[i] && k1 = _ptr[i+1]
+	      var k0 = this._ptr[i];
+	      var k1 = this._ptr[i + 1];
+	      // column pointer
+	      var p = 0;
+	      // loop k within [k0, k1[
+	      for (var k = k0; k < k1; k++) {
+	        // column index
+	        var j = this._index[k];
+	        // check we need to process zeros
+	        if (!skipZeros) {
+	          // zero values
+	          for (var x = p; x < j; x++)
+	            callback(0, [i, x], me);
+	        }
+	        // value @ k
+	        callback(this._values[k], [i, j], me);
+	        // update pointer
+	        p = j + 1;
+	      }
+	      // check we need to process zeros
+	      if (!skipZeros) {
+	        // zero values
+	        for (var y = p; y < columns; y++)
+	          callback(0, [i, y], me);
+	      }
+	    }
+	  };
+
+	  /**
+	   * Create an Array with a copy of the data of the CrsMatrix
+	   * @returns {Array} array
+	   */
+	  CrsMatrix.prototype.toArray = function () {
+	    return _toArray(this, true);
+	  };
+
+	  /**
+	   * Get the primitive value of the CrsMatrix: a two dimensions array
+	   * @returns {Array} array
+	   */
+	  CrsMatrix.prototype.valueOf = function () {
+	    return _toArray(this, false);
+	  };
+
+	  var _toArray = function (matrix, copy) {
+	    // result
+	    var a = [];
+	    // rows and columns
+	    var rows = matrix._size[0];
+	    var columns = matrix._size[1];
+	    // loop rows
+	    for (var i = 0; i < rows; i++) {
+	      // push row
+	      var r = a[i] = [];
+	      // k0 <= k < k1 where k0 = _ptr[i] && k1 = _ptr[i+1]
+	      var k0 = matrix._ptr[i];
+	      var k1 = matrix._ptr[i + 1];
+	      // column pointer
+	      var p = 0;
+	      // loop k is within [k0, k1[
+	      for (var k = k0; k < k1; k++) {
+	        // column index
+	        var j = matrix._index[k];
+	        // zero values
+	        for (var x = p; x < j; x++)
+	          r[x] = 0;
+	        // set value
+	        r[j] = copy ? object.clone(matrix._values[k]) : matrix._values[k];
+	        // update pointer
+	        p = j + 1;
+	      }
+	      // zero values
+	      for (var y = p; y < columns; y++)
+	        r[y] = 0;
+	    }
+	    return a;
+	  };
+
+	  /**
+	   * Get a string representation of the matrix, with optional formatting options.
+	   * @param {Object | Number | Function} [options]  Formatting options. See
+	   *                                                lib/util/number:format for a
+	   *                                                description of the available
+	   *                                                options.
+	   * @returns {String} str
+	   */
+	  CrsMatrix.prototype.format = function (options) {
+	    // rows and columns
+	    var rows = this._size[0];
+	    var columns = this._size[1];
+	    // rows & columns
+	    var str = 'CRS [' + string.format(rows, options) + ' x ' + string.format(columns, options) + '] density: ' + string.format(this._values.length / (rows * columns), options) + '\n';
+	    // loop rows
+	    for (var i = 0; i < rows; i++) {
+	      // k0 <= k < k1 where k0 = _ptr[i] && k1 = _ptr[i+1]
+	      var k0 = this._ptr[i];
+	      var k1 = this._ptr[i + 1];
+	      // loop k within [k0, k1[
+	      for (var k = k0; k < k1; k++) {
+	        // column index
+	        var j = this._index[k];
+	        // append value
+	        str += '\n    (' + string.format(i, options) + ', ' + string.format(j, options) + ') ==> ' + string.format(this._values[k], options);
+	      }
+	    }
+	    return str;
+	  };
+
+	  /**
+	   * Get a string representation of the matrix
+	   * @returns {String} str
+	   */
+	  CrsMatrix.prototype.toString = function () {
+	    return string.format(this.toArray());
+	  };
+
+	  /**
+	   * Get a JSON representation of the matrix
+	   * @returns {Object}
+	   */
+	  CrsMatrix.prototype.toJSON = function () {
+	    return {
+	      mathjs: 'CrsMatrix',
+	      values: this._values,
+	      index: this._index,
+	      ptr: this._ptr,
+	      size: this._size
+	    };
+	  };
+
+	  /**
+	   * Calculates the transpose of the matrix
+	   * @returns {Matrix}
+	   */
+	  CrsMatrix.prototype.transpose = function () {
+	    // rows and columns
+	    var rows = this._size[0];
+	    var columns = this._size[1];
+	    // check columns
+	    if (columns === 0) {
+	      // throw exception
+	      throw new RangeError('Cannot transpose a 2D matrix with no columns (size: ' + string.format(this._size) + ')');
+	    }
+	    // crs transpose is a ccs matrix with the same structure
+	    return new math.type.CcsMatrix({
+	      values: object.clone(this._values),
+	      index: object.clone(this._index),
+	      ptr: object.clone(this._ptr),
+	      size: [columns, rows]
+	    });
+	  };
+
+	  /**
+	   * Get the kth Matrix diagonal.
+	   *
+	   * @param {Number | BigNumber} [k=0]     The kth diagonal where the vector will retrieved.
+	   *
+	   * @returns {Array}                      The array vector with the diagonal values.
+	   */
+	  CrsMatrix.prototype.diagonal = function(k) {
+	    // validate k if any
+	    if (k) {
+	      // convert BigNumber to a number
+	      if (k instanceof BigNumber) 
+	        k = k.toNumber();
+	      // is must be an integer
+	      if (!isNumber(k) || !isInteger(k)) {
+	        throw new TypeError ('The parameter k must be an integer number');
+	      }
+	    }
+	    else {
+	      // default value
+	      k = 0;
+	    }
+
+	    var kSuper = k > 0 ? k : 0;
+	    var kSub = k < 0 ? -k : 0;
+
+	    // rows & columns
+	    var rows = this._size[0];
+	    var columns = this._size[1];
+
+	    // number diagonal values
+	    var n = Math.min(rows - kSub, columns -  kSuper);
+
+	    // diagonal
+	    var values = [];
+	    // loop rows
+	    for (var i = kSub; i < rows && values.length < n; i++) {
+	      // k0 <= k < k1 where k0 = _ptr[i] && k1 = _ptr[i+1]
+	      var k0 = this._ptr[i];
+	      var k1 = this._ptr[i + 1];
+	      // row value flag
+	      var rv = false;
+	      // loop x within [k0, k1[
+	      for (var x = k0; x < k1; x++) {
+	        // column index
+	        var j = this._index[x];
+	        // check column
+	        if (j === i + kSuper - kSub) {
+	          // set flag
+	          rv = true;
+	          // value on this column
+	          values.push(object.clone(this._values[x]));
+	          // exit loop
+	          break;
+	        }
+	        else if (j > i + kSuper - kSub) {
+	          // exit loop, no value on the diagonal for row i
+	          break;
+	        }
+	      }
+	      // check this row has a value set
+	      if (!rv && values.length < n) {
+	        // zero on this column
+	        values.push(0);
+	      }
+	    }
+	    return values;
+	  };
+
+	  /**
+	   * Generate a matrix from a JSON object
+	   * @param {Object} json  An object structured like
+	   *                       `{"mathjs": "CrsMatrix", "values": [], "index": [], "ptr": [], "size": []}`,
+	   *                       where mathjs is optional
+	   * @returns {CrsMatrix}
+	   */
+	  CrsMatrix.fromJSON = function (json) {
+	    return new CrsMatrix(json);
+	  };
+
+	  /**
+	   * Create a diagonal matrix.
+	   *
+	   * @param {Array} size                   The matrix size.
+	   * @param {Number, Array} value          The values for the diagonal.
+	   * @param {Number | BigNumber} [k=0]     The kth diagonal where the vector will be filled in.
+	   *
+	   * @returns {CrsMatrix}
+	   */
+	  CrsMatrix.diagonal = function (size, value, k) {
+	    if (!isArray(size))
+	      throw new TypeError('Array expected, size parameter');
+	    if (size.length !== 2)
+	      throw new Error('Only two dimensions matrix are supported');
+
+	    // map size & validate
+	    size = size.map(function (s) {
+	      // check it is a big number
+	      if (s instanceof BigNumber) {
+	        // convert it
+	        s = s.toNumber();
+	      }
+	      // validate arguments
+	      if (!isNumber(s) || !isInteger(s) || s < 1) {
+	        throw new Error('Size values must be positive integers');
+	      } 
+	      return s;
+	    });
+
+	    // validate k if any
+	    if (k) {
+	      // convert BigNumber to a number
+	      if (k instanceof BigNumber) 
+	        k = k.toNumber();
+	      // is must be an integer
+	      if (!isNumber(k) || !isInteger(k)) {
+	        throw new TypeError ('The parameter k must be an integer number');
+	      }
+	    }
+	    else {
+	      // default value
+	      k = 0;
+	    }
+
+	    var kSuper = k > 0 ? k : 0;
+	    var kSub = k < 0 ? -k : 0;
+
+	    // rows and columns
+	    var rows = size[0];
+	    var columns = size[1];
+
+	    // number of non-zero items
+	    var n = Math.min(rows - kSub, columns -  kSuper);
+
+	    // value extraction function
+	    var _value;
+
+	    // check value
+	    if (isArray(value)) {
+	      // validate array
+	      if (value.length !== n) {
+	        // number of values in array must be n
+	        throw new Error('Invalid value array length');
+	      }
+	      // define function
+	      _value = function (i) {
+	        // return value @ i
+	        return value[i];
+	      };
+	    }
+	    else {
+	      // define function
+	      _value = function () {
+	        // return value
+	        return value;
+	      };
+	    }
+
+	    // create arrays
+	    var values = [];
+	    var index = [];
+	    var ptr = [];
+
+	    // loop items
+	    for (var i = 0; i < rows; i++) {
+	      // number of rows with value
+	      ptr.push(values.length);
+	      // diagonal index
+	      var j = i - kSub;
+	      // check we need to set diagonal value
+	      if (j >= 0 && j < n) {
+	        // get value @ j
+	        var v = _value(j);
+	        // check for zero
+	        if (!math.equal(v, 0)) {
+	          // column
+	          index.push(j + kSuper);
+	          // add value
+	          values.push(v);
+	        }
+	      }
+	    }
+	    // last value should be number of values
+	    ptr.push(values.length);
+	    // create CrsMatrix
+	    return new CrsMatrix({
+	      values: values,
+	      index: index,
+	      ptr: ptr,
+	      size: [rows, columns]
+	    });
+	  };
+
+	  /**
+	   * Calculate the trace of a matrix: the sum of the elements on the main
+	   * diagonal of a square matrix.
+	   *
+	   * See also:
+	   *
+	   *    diagonal
+	   *
+	   * @returns {Number}       The matrix trace
+	   */
+	  CrsMatrix.prototype.trace = function () {
+	    // size
+	    var size = this._size;
+	    // check dimensions
+	    var rows = size[0];
+	    var columns = size[1];
+	    // matrix must be square
+	    if (rows === columns) {
+	      // calulate sum
+	      var sum = 0;
+	      // check we have data (avoid looping rows)
+	      if (this._values.length > 0) {
+	        // loop rows
+	        for (var i = 0; i < rows; i++) {
+	          // k0 <= k < k1 where k0 = _ptr[i] && k1 = _ptr[i+1]
+	          var k0 = this._ptr[i];
+	          var k1 = this._ptr[i + 1];
+	          // loop k within [k0, k1[
+	          for (var k = k0; k < k1; k++) {
+	            // column index
+	            var j = this._index[k];
+	            // check row
+	            if (i === j) {
+	              // accumulate value
+	              sum = math.add(sum, this._values[k]);
+	              // exit loop
+	              break;
+	            }
+	            if (j > i) {
+	              // exit loop, no value on the diagonal for column j
+	              break;
+	            }
+	          }
+	        }
+	      }
+	      // return trace
+	      return sum;
+	    }
+	    throw new RangeError('Matrix must be square (size: ' + string.format(size) + ')');        
+	  };
+	  
+	  /**
+	   * Multiply the matrix values times the argument.
+	   *
+	   * @param  {Number | BigNumber | Boolean | Complex | Unit | Array | Matrix | null} Value to multiply.
+	   *
+	   * @return {Number | BigNumber | Complex | Unit | Matrix}
+	   */
+	  CrsMatrix.prototype.multiply = function (value) {
+	    // check dimensions
+	    var rows = this._size[0];
+	    var columns = this._size[1];
+
+	    // check value is a matrix
+	    if (value instanceof Matrix) {
+	      // matrix size
+	      var z = value.size();
+	      // check value is a vector
+	      if (z.length === 1) {
+	        // mutiply matrix x vector array
+	        return _multiply(this, z[0], 1, function (i) {
+	          // value[i]
+	          return value.get([i]);
+	        });
+	      }
+	      // check two dimensions matrix
+	      if (z.length === 2) {        
+	        // mutiply matrix x matrix
+	        return _multiply(this, z[0], z[1], function (i, j) {
+	          // value[i, j]
+	          return value.get([i, j]);
+	        });
+	      }
+	      throw new Error('Can only multiply a 1 or 2 dimensional matrix ' +
+	                      '(value has ' + z.length + ' dimensions)');
+	    }
+
+	    // check value is an array
+	    if (isArray(value)) {
+	      // array size
+	      var s = array.size(value);
+	      // check value is a vector
+	      if (s.length === 1) {
+	        // mutiply matrix x vector array
+	        return _multiply(this, s[0], 1, function (i) {
+	          // value[i]
+	          return value[i];
+	        });
+	      }
+	      if (s.length === 2) {
+	        // mutiply matrix x array
+	        return _multiply(this, s[0], s[1], function (i, j) {
+	          // value[i, j]
+	          return value[i][j];
+	        });
+	      }
+	      throw new Error('Can only multiply a 1 or 2 dimensional matrix ' +
+	                      '(value has ' + s.length + ' dimensions)');
+	    }
+
+	    var callback = function (v) {
+	      return math.multiply(v, value);
+	    };
+
+	    // map non zero elements
+	    return _map(this, 0, rows - 1, 0, columns - 1, callback, false);
+	  };
+	  
+	  var _multiply = function (matrix, r, c, get) {
+
+	    // matrix dimensions
+	    var rows = matrix._size[0];
+	    var columns = matrix._size[1];
+
+	    // check dimensions match
+	    if (columns !== r) {
+	      // throw error
+	      throw new RangeError('Dimension mismatch in multiplication. ' +
+	                           'Columns of A must match length of B ' +
+	                           '(A is ' + rows + 'x' + columns +
+	                           ', B is ' + r + ', ' +
+	                           columns + ' != ' + r + ')');
+	    }
+
+	    // result arrays
+	    var values = [];
+	    var index = [];
+	    var ptr = [];
+
+	    // loop rows
+	    for (var i = 0; i < rows; i++) {
+	      // update ptr
+	      ptr.push(values.length);
+	      // k0 <= k < k1 where k0 = _ptr[i] && k1 = _ptr[i+1]
+	      var k0 = matrix._ptr[i];
+	      var k1 = matrix._ptr[i + 1];
+	      // loop value columns
+	      for (var z = 0; z < c; z++) {
+	        // value @ (i, x)
+	        var value = 0;
+	        // loop k within [k0, k1[
+	        for (var k = k0; k < k1; k++) {
+	          // column
+	          var j = matrix._index[k];
+	          // multiply & aggregate
+	          value = math.add(value, math.multiply(matrix._values[k], get(j, z)));
+	        }
+	        // check value is different than zero
+	        if (!math.equal(value, 0)) {
+	          // push value & column
+	          values.push(value);
+	          index.push(z);
+	        }        
+	      }
+	    }
+	    // update ptr
+	    ptr.push(values.length);
+
+	    // check we need to squeeze the result into a scalar
+	    if (rows === 1 && c === 1)
+	      return values.length === 1 ? values[0] : 0;
+
+	    // return CRS matrix
+	    return new CrsMatrix({
+	      values: values,
+	      index: index,
+	      ptr: ptr,
+	      size: [rows, c]
+	    });
+	  };
+
+	  return CrsMatrix;
+	};
+
+/***/ },
+/* 17 */
+/***/ function(module, exports, __webpack_require__) {
+
+	'use strict';
+
+	var util = __webpack_require__(174);
+	var DimensionError = __webpack_require__(171);
+
+	var string = util.string;
+	var array = util.array;
+	var object = util.object;
+
+	var isArray = Array.isArray;
+	var isNumber = util.number.isNumber;
+	var isInteger = util.number.isInteger;
+
+	var validateIndex = array.validateIndex;
+
+	module.exports = function (math) {
+
+	  var Index = math.type.Index,
+	      BigNumber = math.type.BigNumber,
+	      Matrix = math.type.Matrix;
+	  
+	  function DenseMatrix(data) {
+	    if (!(this instanceof DenseMatrix))
+	      throw new SyntaxError('Constructor must be called with the new operator');
+
+	    if (data instanceof Matrix) {
+	      // check data is a DenseMatrix
+	      if (data.type === 'DenseMatrix') {
+	        // clone data & size
+	        this._data = object.clone(data._data);
+	        this._size = object.clone(data._size);
+	      }
+	      else {
+	        // build data from existing matrix
+	        this._data = data.toArray();
+	        this._size = data.size();
+	      }
+	    }
+	    else if (data && isArray(data.data) && isArray(data.size)) {
+	      // initialize fields from JSON representation
+	      this._data = data.data;
+	      this._size = data.size;
+	    }
+	    else if (isArray(data)) {
+	      // replace nested Matrices with Arrays
+	      this._data = preprocess(data);
+	      // verify the size of the array, TODO: compute size while processing array
+	      this._size = array.size(this._data);
+	    }
+	    else if (data) {
+	      // unsupported type
+	      throw new TypeError('Unsupported type of data (' + util.types.type(data) + ')');
+	    }
+	    else {
+	      // nothing provided
+	      this._data = [];
+	      this._size = [0];
+	    }
+	  }
+	  
+	  DenseMatrix.prototype = new math.type.Matrix();
+
+	  DenseMatrix.prototype.type = 'DenseMatrix';
+
+	  /**
+	   * Get the storage format used by the matrix.
+	   *
+	   * Usage:
+	   *     var format = matrix.storage()                   // retrieve storage format
+	   *
+	   * @return {string}           The storage format.
+	   */
+	  DenseMatrix.prototype.storage = function () {
+	    return 'dense';
+	  };
+	  
+	  /**
+	   * Get a subset of the matrix, or replace a subset of the matrix.
+	   *
+	   * Usage:
+	   *     var subset = matrix.subset(index)               // retrieve subset
+	   *     var value = matrix.subset(index, replacement)   // replace subset
+	   *
+	   * @param {Index} index
+	   * @param {Array | DenseMatrix | *} [replacement]
+	   * @param {*} [defaultValue=0]      Default value, filled in on new entries when
+	   *                                  the matrix is resized. If not provided,
+	   *                                  new matrix elements will be filled with zeros.
+	   */
+	  DenseMatrix.prototype.subset = function (index, replacement, defaultValue) {
+	    switch (arguments.length) {
+	      case 1:
+	        return _get(this, index);
+
+	        // intentional fall through
+	      case 2:
+	      case 3:
+	        return _set(this, index, replacement, defaultValue);
+
+	      default:
+	        throw new SyntaxError('Wrong number of arguments');
+	    }
+	  };
+	  
+	  /**
+	   * Get a single element from the matrix.
+	   * @param {Number[]} index   Zero-based index
+	   * @return {*} value
+	   */
+	  DenseMatrix.prototype.get = function (index) {
+	    if (!isArray(index))
+	      throw new TypeError('Array expected');
+	    if (index.length != this._size.length)
+	      throw new DimensionError(index.length, this._size.length);
+
+	    // check index
+	    for (var x = 0; x < index.length; x++)
+	      validateIndex(index[x], this._size[x]);
+
+	    var data = this._data;
+	    for (var i = 0, ii = index.length; i < ii; i++) {
+	      var index_i = index[i];
+	      validateIndex(index_i, data.length);
+	      data = data[index_i];
+	    }
+
+	    return object.clone(data);
+	  };
+	  
+	  /**
+	   * Replace a single element in the matrix.
+	   * @param {Number[]} index   Zero-based index
+	   * @param {*} value
+	   * @param {*} [defaultValue]        Default value, filled in on new entries when
+	   *                                  the matrix is resized. If not provided,
+	   *                                  new matrix elements will be left undefined.
+	   * @return {DenseMatrix} self
+	   */
+	  DenseMatrix.prototype.set = function (index, value, defaultValue) {
+	    if (!isArray(index))
+	      throw new TypeError('Array expected');
+	    if (index.length < this._size.length)
+	      throw new DimensionError(index.length, this._size.length, '<');
+
+	    var i, ii, index_i;
+
+	    // enlarge matrix when needed
+	    var size = index.map(function (i) {
+	      return i + 1;
+	    });
+	    _fit(this, size, defaultValue);
+
+	    // traverse over the dimensions
+	    var data = this._data;
+	    for (i = 0, ii = index.length - 1; i < ii; i++) {
+	      index_i = index[i];
+	      validateIndex(index_i, data.length);
+	      data = data[index_i];
+	    }
+
+	    // set new value
+	    index_i = index[index.length - 1];
+	    validateIndex(index_i, data.length);
+	    data[index_i] = value;
+
+	    return this;
+	  };
+	  
+	  /**
+	   * Get a submatrix of this matrix
+	   * @param {DenseMatrix} matrix
+	   * @param {Index} index   Zero-based index
+	   * @private
+	   */
+	  function _get (matrix, index) {
+	    if (!(index instanceof Index)) {
+	      throw new TypeError('Invalid index');
+	    }
+
+	    var isScalar = index.isScalar();
+	    if (isScalar) {
+	      // return a scalar
+	      return matrix.get(index.min());
+	    }
+	    else {
+	      // validate dimensions
+	      var size = index.size();
+	      if (size.length != matrix._size.length) {
+	        throw new DimensionError(size.length, matrix._size.length);
+	      }
+
+	      // validate if any of the ranges in the index is out of range
+	      var min = index.min();
+	      var max = index.max();
+	      for (var i = 0, ii = matrix._size.length; i < ii; i++) {
+	        validateIndex(min[i], matrix._size[i]);
+	        validateIndex(max[i], matrix._size[i]);
+	      }
+
+	      // retrieve submatrix
+	      // TODO: more efficient when creating an empty matrix and setting _data and _size manually
+	      return new DenseMatrix(_getSubmatrix(matrix._data, index, size.length, 0));
+	    }
+	  }
+	  
+	  /**
+	   * Recursively get a submatrix of a multi dimensional matrix.
+	   * Index is not checked for correct number or length of dimensions.
+	   * @param {Array} data
+	   * @param {Index} index
+	   * @param {number} dims   Total number of dimensions
+	   * @param {number} dim    Current dimension
+	   * @return {Array} submatrix
+	   * @private
+	   */
+	  function _getSubmatrix (data, index, dims, dim) {
+	    var last = (dim == dims - 1);
+	    var range = index.range(dim);
+
+	    if (last) {
+	      return range.map(function (i) {
+	        return data[i];
+	      });
+	    }
+	    else {
+	      return range.map(function (i) {
+	        var child = data[i];
+	        return _getSubmatrix(child, index, dims, dim + 1);
+	      });
+	    }
+	  }
+	  
+	  /**
+	   * Replace a submatrix in this matrix
+	   * Indexes are zero-based.
+	   * @param {DenseMatrix} matrix
+	   * @param {Index} index
+	   * @param {DenseMatrix | Array | *} submatrix
+	   * @param {*} defaultValue          Default value, filled in on new entries when
+	   *                                  the matrix is resized.
+	   * @return {DenseMatrix} matrix
+	   * @private
+	   */
+	  function _set (matrix, index, submatrix, defaultValue) {
+	    if (!(index instanceof Index)) {
+	      throw new TypeError('Invalid index');
+	    }
+
+	    // get index size and check whether the index contains a single value
+	    var iSize = index.size(),
+	        isScalar = index.isScalar();
+
+	    // calculate the size of the submatrix, and convert it into an Array if needed
+	    var sSize;
+	    if (submatrix instanceof math.type.Matrix) {
+	      sSize = submatrix.size();
+	      submatrix = submatrix.valueOf();
+	    }
+	    else {
+	      sSize = array.size(submatrix);
+	    }
+
+	    if (isScalar) {
+	      // set a scalar
+
+	      // check whether submatrix is a scalar
+	      if (sSize.length !== 0) {
+	        throw new TypeError('Scalar expected');
+	      }
+
+	      matrix.set(index.min(), submatrix, defaultValue);
+	    }
+	    else {
+	      // set a submatrix
+
+	      // validate dimensions
+	      if (iSize.length < matrix._size.length) {
+	        throw new DimensionError(iSize.length, matrix._size.length, '<');
+	      }
+
+	      if (sSize.length < iSize.length) {
+	        // calculate number of missing outer dimensions
+	        var i = 0;
+	        var outer = 0;
+	        while (iSize[i] === 1 && sSize[i] === 1) {
+	          i++;
+	        }
+	        while (iSize[i] === 1) {
+	          outer++;
+	          i++;
+	        }
+
+	        // unsqueeze both outer and inner dimensions
+	        submatrix = array.unsqueeze(submatrix, iSize.length, outer, sSize);
+	      }
+
+	      // check whether the size of the submatrix matches the index size
+	      if (!object.deepEqual(iSize, sSize)) {
+	        throw new DimensionError(iSize, sSize, '>');
+	      }
+
+	      // enlarge matrix when needed
+	      var size = index.max().map(function (i) {
+	        return i + 1;
+	      });
+	      _fit(matrix, size, defaultValue);
+
+	      // insert the sub matrix
+	      var dims = iSize.length,
+	          dim = 0;
+	      _setSubmatrix (matrix._data, index, submatrix, dims, dim);
+	    }
+
+	    return matrix;
+	  }
+	  
+	  /**
+	   * Replace a submatrix of a multi dimensional matrix.
+	   * @param {Array} data
+	   * @param {Index} index
+	   * @param {Array} submatrix
+	   * @param {number} dims   Total number of dimensions
+	   * @param {number} dim
+	   * @private
+	   */
+	  function _setSubmatrix (data, index, submatrix, dims, dim) {
+	    var last = (dim == dims - 1),
+	        range = index.range(dim);
+
+	    if (last) {
+	      range.forEach(function (dataIndex, subIndex) {
+	        validateIndex(dataIndex);
+	        data[dataIndex] = submatrix[subIndex];
+	      });
+	    }
+	    else {
+	      range.forEach(function (dataIndex, subIndex) {
+	        validateIndex(dataIndex);
+	        _setSubmatrix(data[dataIndex], index, submatrix[subIndex], dims, dim + 1);
+	      });
+	    }
+	  }
+	  
+	  /**
+	   * Resize the matrix to the given size. Returns a copy of the matrix when
+	   * `copy=true`, otherwise return the matrix itself (resize in place).
+	   *
+	   * @param {Number[]} size           The new size the matrix should have.
+	   * @param {*} [defaultValue=0]      Default value, filled in on new entries.
+	   *                                  If not provided, the matrix elements will
+	   *                                  be filled with zeros.
+	   * @param {boolean} [copy]          Return a resized copy of the matrix
+	   *
+	   * @return {Matrix}                 The resized matrix
+	   */
+	  DenseMatrix.prototype.resize = function (size, defaultValue, copy) {
+	    // validate arguments
+	    if (!isArray(size))
+	      throw new TypeError('Array expected');
+
+	    // matrix to resize
+	    var m = copy ? this.clone() : this;
+	    // resize matrix
+	    return _resize(m, size, defaultValue);
+	  };
+	  
+	  var _resize = function (matrix, size, defaultValue) {
+	    // check size
+	    if (size.length === 0) {
+	      // first value in matrix
+	      var v = matrix._data;
+	      // go deep
+	      while (isArray(v)) {
+	        v = v[0];
+	      }
+	      return object.clone(v);
+	    }
+	    // resize matrix
+	    matrix._size = object.clone(size);
+	    matrix._data = array.resize(matrix._data, matrix._size, defaultValue);
+	    // return matrix
+	    return matrix;
+	  };
+	  
+	  /**
+	   * Enlarge the matrix when it is smaller than given size.
+	   * If the matrix is larger or equal sized, nothing is done.
+	   * @param {DenseMatrix} matrix           The matrix to be resized
+	   * @param {Number[]} size
+	   * @param {*} defaultValue          Default value, filled in on new entries.
+	   * @private
+	   */
+	  function _fit(matrix, size, defaultValue) {
+	    var newSize = object.clone(matrix._size),
+	        changed = false;
+
+	    // add dimensions when needed
+	    while (newSize.length < size.length) {
+	      newSize.push(0);
+	      changed = true;
+	    }
+
+	    // enlarge size when needed
+	    for (var i = 0, ii = size.length; i < ii; i++) {
+	      if (size[i] > newSize[i]) {
+	        newSize[i] = size[i];
+	        changed = true;
+	      }
+	    }
+
+	    if (changed) {
+	      // resize only when size is changed
+	      _resize(matrix, newSize, defaultValue);
+	    }
+	  }
+	  
+	  /**
+	   * Create a clone of the matrix
+	   * @return {DenseMatrix} clone
+	   */
+	  DenseMatrix.prototype.clone = function () {
+	    var m = new DenseMatrix({
+	      data: object.clone(this._data),
+	      size: object.clone(this._size)
+	    });
+	    return m;
+	  };
+	  
+	  /**
+	   * Retrieve the size of the matrix.
+	   * @returns {Number[]} size
+	   */
+	  DenseMatrix.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 function is invoked with three
+	   *                              parameters: the value of the element, the index
+	   *                              of the element, and the Matrix being traversed.
+	   *
+	   * @return {DenseMatrix} matrix
+	   */
+	  DenseMatrix.prototype.map = function (callback) {
+	    // matrix instance
+	    var me = this;
+	    var recurse = function (value, index) {
+	      if (isArray(value)) {
+	        return value.map(function (child, i) {
+	          return recurse(child, index.concat(i));
+	        });
+	      }
+	      else {
+	        return callback(value, index, me);
+	      }
+	    };
+	    // return dense format
+	    return new DenseMatrix({
+	      data: recurse(this._data, []),
+	      size: object.clone(this._size)
+	    });
+	  };
+	  
+	  /**
+	   * Execute a callback function on each entry of the matrix.
+	   * @param {function} callback   The callback function is invoked with three
+	   *                              parameters: the value of the element, the index
+	   *                              of the element, and the Matrix being traversed.
+	   */
+	  DenseMatrix.prototype.forEach = function (callback) {
+	    // matrix instance
+	    var me = this;
+	    var recurse = function (value, index) {
+	      if (isArray(value)) {
+	        value.forEach(function (child, i) {
+	          recurse(child, index.concat(i));
+	        });
+	      }
+	      else {
+	        callback(value, index, me);
+	      }
+	    };
+	    recurse(this._data, []);
+	  };
+	  
+	  /**
+	   * Create an Array with a copy of the data of the DenseMatrix
+	   * @returns {Array} array
+	   */
+	  DenseMatrix.prototype.toArray = function () {
+	    return object.clone(this._data);
+	  };
+	  
+	  /**
+	   * Get the primitive value of the DenseMatrix: a multidimensional array
+	   * @returns {Array} array
+	   */
+	  DenseMatrix.prototype.valueOf = function () {
+	    return this._data;
+	  };
+	  
+	  /**
+	   * Get a string representation of the matrix, with optional formatting options.
+	   * @param {Object | Number | Function} [options]  Formatting options. See
+	   *                                                lib/util/number:format for a
+	   *                                                description of the available
+	   *                                                options.
+	   * @returns {String} str
+	   */
+	  DenseMatrix.prototype.format = function (options) {
+	    return string.format(this._data, options);
+	  };
+	  
+	  /**
+	   * Get a string representation of the matrix
+	   * @returns {String} str
+	   */
+	  DenseMatrix.prototype.toString = function () {
+	    return string.format(this._data);
+	  };
+	  
+	  /**
+	   * Get a JSON representation of the matrix
+	   * @returns {Object}
+	   */
+	  DenseMatrix.prototype.toJSON = function () {
+	    return {
+	      mathjs: 'DenseMatrix',
+	      data: this._data,
+	      size: this._size
+	    };
+	  };
+	  
+	  /**
+	   * Calculates the transpose of the matrix
+	   * @returns {Matrix}
+	   */
+	  DenseMatrix.prototype.transpose = function () {
+	    // check dimensions
+	    switch (this._size.length) {
+	        case 1:
+	          // vector
+	          return this.clone();
+	        case 2:
+	          // rows and columns
+	          var rows = this._size[0];
+	          var columns = this._size[1];
+	          // check columns
+	          if (columns === 0) {
+	            // throw exception
+	            throw new RangeError('Cannot transpose a 2D matrix with no columns (size: ' + string.format(this._size) + ')');
+	          }
+	          // transposed matrix data
+	          var transposed = [];
+	          var transposedRow;
+	          // loop columns
+	          for (var j = 0; j < columns; j++) {
+	            // initialize row
+	            transposedRow = transposed[j] = [];
+	            // loop rows
+	            for (var i = 0; i < rows; i++) {
+	              // set data
+	              transposedRow[i] = object.clone(this._data[i][j]);
+	            }
+	          }
+	          // return matrix
+	          return new DenseMatrix({
+	            data: transposed,
+	            size: [columns, rows]
+	          });
+	        default:
+	          // multi dimensional
+	          throw new RangeError('Matrix must be two dimensional (size: ' + string.format(this._size) + ')');
+	    }
+	  };
+	  
+	  /**
+	   * Get the kth Matrix diagonal.
+	   *
+	   * @param {Number | BigNumber} [k=0]     The kth diagonal where the vector will retrieved.
+	   *
+	   * @returns {Array}                      The array vector with the diagonal values.
+	   */
+	  DenseMatrix.prototype.diagonal = function(k) {
+	    // validate k if any
+	    if (k) {
+	      // convert BigNumber to a number
+	      if (k instanceof BigNumber) 
+	        k = k.toNumber();
+	      // is must be an integer
+	      if (!isNumber(k) || !isInteger(k)) {
+	        throw new TypeError ('The parameter k must be an integer number');
+	      }
+	    }
+	    else {
+	      // default value
+	      k = 0;
+	    }
+
+	    var kSuper = k > 0 ? k : 0;
+	    var kSub = k < 0 ? -k : 0;
+
+	    // rows & columns
+	    var rows = this._size[0];
+	    var columns = this._size[1];
+
+	    // number diagonal values
+	    var n = Math.min(rows - kSub, columns -  kSuper);
+	    
+	    // x is a matrix get diagonal from matrix
+	    var vector = [];
+	    
+	    // loop rows
+	    for (var i = 0; i < n; i++) {
+	      vector[i] = object.clone(this._data[i + kSub][i + kSuper]);
+	    }
+	    return vector;
+	  };
+	  
+	  /**
+	   * Create a diagonal matrix.
+	   *
+	   * @param {Array} size                   The matrix size.
+	   * @param {Number, Array} value          The values for the diagonal.
+	   * @param {Number | BigNumber} [k=0]     The kth diagonal where the vector will be filled in.
+	   * @param {Number} [defaultValue]        The default value for non-diagonal
+	   *
+	   * @returns {DenseMatrix}
+	   */
+	  DenseMatrix.diagonal = function (size, value, k, defaultValue) {
+	    if (!isArray(size))
+	      throw new TypeError('Array expected, size parameter');
+	    if (size.length !== 2)
+	      throw new Error('Only two dimensions matrix are supported');
+
+	    // map size & validate
+	    size = size.map(function (s) {
+	      // check it is a big number
+	      if (s instanceof BigNumber) {
+	        // convert it
+	        s = s.toNumber();
+	      }
+	      // validate arguments
+	      if (!isNumber(s) || !isInteger(s) || s < 1) {
+	        throw new Error('Size values must be positive integers');
+	      } 
+	      return s;
+	    });
+
+	    // validate k if any
+	    if (k) {
+	      // convert BigNumber to a number
+	      if (k instanceof BigNumber) 
+	        k = k.toNumber();
+	      // is must be an integer
+	      if (!isNumber(k) || !isInteger(k)) {
+	        throw new TypeError ('The parameter k must be an integer number');
+	      }
+	    }
+	    else {
+	      // default value
+	      k = 0;
+	    }
+
+	    var kSuper = k > 0 ? k : 0;
+	    var kSub = k < 0 ? -k : 0;
+	    
+	    // rows and columns
+	    var rows = size[0];
+	    var columns = size[1];
+
+	    // number of non-zero items
+	    var n = Math.min(rows - kSub, columns -  kSuper);
+
+	    // value extraction function
+	    var _value;
+
+	    // check value
+	    if (isArray(value)) {
+	      // validate array
+	      if (value.length !== n) {
+	        // number of values in array must be n
+	        throw new Error('Invalid value array length');
+	      }
+	      // define function
+	      _value = function (i) {
+	        // return value @ i
+	        return value[i];
+	      };
+	    }
+	    else {
+	      // define function
+	      _value = function () {
+	        // return value
+	        return value;
+	      };
+	    }
+
+	    // empty array
+	    var data = [];
+
+	    // check we need to resize array
+	    if (size.length > 0) {
+	      // resize array
+	      data = array.resize(data, size, defaultValue);
+	      // fill diagonal
+	      for (var d = 0; d < n; d++) {
+	        data[d + kSub][d + kSuper] = _value(d);
+	      }
+	    }
+	    
+	    // create DenseMatrix
+	    return new DenseMatrix({
+	      data: data,
+	      size: [rows, columns]
+	    });
+	  };
+	  
+	  /**
+	   * Calculate the trace of a matrix: the sum of the elements on the main
+	   * diagonal of a square matrix.
+	   *
+	   * See also:
+	   *
+	   *    diagonal
+	   *
+	   * @returns {Number}       The matrix trace
+	   */
+	  DenseMatrix.prototype.trace = function () {
+	    // size & data
+	    var size = this._size;
+	    var data = this._data;
+	    // check dimensions
+	    switch (size.length) {
+	      case 1:
+	        // vector
+	        if (size[0] == 1) {
+	          // return data[0]
+	          return object.clone(data[0]);
+	        }
+	        throw new RangeError('Matrix must be square (size: ' + string.format(size) + ')');
+	      case 2:
+	        // two dimensional array
+	        var rows = size[0];
+	        var cols = size[1];
+	        if (rows === cols) {
+	          // calulate sum
+	          var sum = 0;
+	          // loop diagonal
+	          for (var i = 0; i < rows; i++)
+	            sum = math.add(sum, data[i][i]);
+	          // return trace
+	          return sum;
+	        }
+	        throw new RangeError('Matrix must be square (size: ' + string.format(size) + ')');        
+	      default:
+	        // multi dimensional array
+	        throw new RangeError('Matrix must be two dimensional (size: ' + string.format(size) + ')');
+	    }
+	  };
+
+	  /**
+	   * Generate a matrix from a JSON object
+	   * @param {Object} json  An object structured like
+	   *                       `{"mathjs": "DenseMatrix", data: [], size: []}`,
+	   *                       where mathjs is optional
+	   * @returns {DenseMatrix}
+	   */
+	  DenseMatrix.fromJSON = function (json) {
+	    return new DenseMatrix(json);
+	  };
+
+	  /**
+	   * Multiply the matrix values times the argument.
+	   *
+	   * @param  {Number | BigNumber | Boolean | Complex | Unit | Array | Matrix | null} Value to multiply.
+	   *
+	   * @return {Number | BigNumber | Complex | Unit | Matrix}
+	   */
+	  DenseMatrix.prototype.multiply = function (value) {
+	    // process matrix size
+	    switch(this._size.length) {
+	      case 1:
+	        // multiply vector
+	        return _multiplyVector(this, this._size[0], value);
+	      case 2:
+	        // multiply matrix
+	        return _multiplyMatrix(this, this._size[0], this._size[1], value);
+	      default:
+	        throw new Error('Can only multiply a 1 or 2 dimensional matrix ' +
+	                        '(matrix has ' + this._size.length + ' dimensions)');
+	    }
+	  };
+	  
+	  var _multiplyVector = function (matrix, m, value) {
+	    // check value is a matrix
+	    if (value instanceof Matrix) {
+	      // matrix size
+	      var z = value.size();
+	      // check value is a vector
+	      if (z.length === 1) {
+	        // vectors must have same length
+	        if (z[0] !== m)
+	          throw new RangeError('Dimension mismatch in multiplication. Vectors must have the same length.');
+	        // multiply vector x vector
+	        return _multiplyVectorVector(matrix, m, function (i) {
+	          // value[i]
+	          return value.get([i]);
+	        });
+	      }
+	      // check two dimensions matrix
+	      if (z.length === 2) {        
+	        // vector length must be equal rows in matrix
+	        if (z[0] !== m)
+	          throw new RangeError('Dimension mismatch in multiplication. Matrix rows and Vector length must be equal.');
+	        // mutiply vector x matrix
+	        return _multiplyVectorMatrix(matrix, m, z[1], function (i, j) {
+	          // value[i]
+	          return value.get([i, j]);
+	        });
+	      }
+	      throw new Error('Can only multiply a 1 or 2 dimensional matrix ' +
+	                      '(value has ' + z.length + ' dimensions)');
+	    }
+
+	    // check value is an array
+	    if (isArray(value)) {
+	      // array size
+	      var s = array.size(value);
+	      // check value is a vector
+	      if (s.length === 1) {
+	        // vectors must have same length
+	        if (s[0] !== m)
+	          throw new RangeError('Dimension mismatch in multiplication. Vectors must have the same length.');
+	        // multiply vector x vector
+	        return _multiplyVectorVector(matrix, m, function (i) {
+	          // value[i]
+	          return value[i];
+	        });
+	      }
+	      if (s.length === 2) {
+	        // vector length must be equal rows in matrix
+	        if (s[0] !== m)
+	          throw new RangeError('Dimension mismatch in multiplication. Matrix rows and Vector length must be equal.');
+	        // mutiply vector x matrix
+	        return _multiplyVectorMatrix(matrix, m, s[1], function (i, j) {
+	          // value[i]
+	          return value[i][j];
+	        });
+	      }
+	      throw new Error('Can only multiply a 1 or 2 dimensional matrix ' +
+	                      '(value has ' + s.length + ' dimensions)');
+	    }
+	    
+	    // value is a scalar
+	    return matrix.map(function (v) {
+	      return math.multiply(value, v);
+	    });
+	  };
+	  
+	  var _multiplyVectorVector = function (matrix, m, get) {
+	    // check empty vector
+	    if (m === 0)
+	      throw new Error('Cannot multiply two empty vectors');
+	    // result
+	    var result = 0;
+	    // loop data
+	    for (var i = 0; i < m; i++) {
+	      // multiply and accumulate
+	      result = math.add(result, math.multiply(matrix._data[i], get(i)));
+	    }
+	    return result;
+	  };
+	                        
+	  var _multiplyVectorMatrix = function (matrix, m, n, get) {
+	    // result
+	    var result = [];
+	    // loop columns in matrix
+	    for (var j = 0; j < n; j++) {
+	      // sum
+	      var sum = 0;
+	      // loop vector
+	      for (var i = 0; i < m; i++) {
+	        // multiply and accumulate
+	        sum = math.add(sum, math.multiply(matrix._data[i], get(i, j)));
+	      }
+	      result[j] = sum;
+	    }
+	    // check we need to squeeze the result into a scalar
+	    if (n === 1)
+	      return result[0];
+	    // return matrix
+	    return new DenseMatrix({
+	      data: result,
+	      size: [n]
+	    });
+	  };
+	      
+	  var _multiplyMatrix = function (matrix, m, n, value) {
+	    // check value is a matrix
+	    if (value instanceof Matrix) {
+	      // matrix size
+	      var z = value.size();
+	      // check value is a vector
+	      if (z.length === 1) {
+	        // vectors must have same length
+	        if (z[0] !== n)
+	          throw new RangeError('Dimension mismatch in multiplication. Matrix columns must match vector length.');
+	        // multiply matrix vector
+	        return _multiplyMatrixVector(matrix, m, n, function (i) {
+	          // value[i]
+	          return value.get([i]);
+	        });
+	      }
+	      // check two dimensions matrix
+	      if (z.length === 2) {        
+	        // vector length must be equal rows in matrix
+	        if (z[0] !== n) {
+	          throw new RangeError('Dimension mismatch in multiplication. ' +
+	                               'Columns of A must match length of B ' +
+	                               '(A is ' + m + 'x' + n +
+	                               ', B is ' + z[0] + ', ' +
+	                               n + ' != ' + z[0] + ')');
+	        }
+	        // mutiply vector x matrix
+	        return _multiplyMatrixMatrix(matrix, m, n, z[1], function (i, j) {
+	          // value[i, j]
+	          return value.get([i, j]);
+	        });
+	      }
+	      throw new Error('Can only multiply a 1 or 2 dimensional matrix ' +
+	                      '(value has ' + z.length + ' dimensions)');
+	    }
+
+	    // check value is an array
+	    if (isArray(value)) {
+	      // array size
+	      var s = array.size(value);
+	      // check value is a vector
+	      if (s.length === 1) {
+	        // vectors must have same length
+	        if (s[0] !== n)
+	          throw new RangeError('Dimension mismatch in multiplication. Matrix columns must match vector length.');
+	        // multiply matrix vector
+	        return _multiplyMatrixVector(matrix, m, n, function (i) {
+	          // value[i]
+	          return value[i];
+	        });
+	      }
+	      if (s.length === 2) {
+	        // vector length must be equal rows in matrix
+	        if (s[0] !== n) {
+	          throw new RangeError('Dimension mismatch in multiplication. ' +
+	                               'Columns of A must match length of B ' +
+	                               '(A is ' + m + 'x' + n +
+	                               ', B is ' + s[0] + ', ' +
+	                               n + ' != ' + s[0] + ')');
+	        }
+	        // mutiply vector x matrix
+	        return _multiplyMatrixMatrix(matrix, m, n, s[1], function (i, j) {
+	          // value[i, j]
+	          return value[i][j];
+	        });
+	      }
+	      throw new Error('Can only multiply a 1 or 2 dimensional matrix ' +
+	                      '(value has ' + s.length + ' dimensions)');
+	    }
+
+	    // value is a scalar
+	    return matrix.map(function (v) {
+	      return math.multiply(value, v);
+	    });
+	  };
+	  
+	  var _multiplyMatrixVector = function (matrix, m, n, get) {
+	    // result
+	    var result = [];
+	    // loop matrix rows
+	    for (var i = 0; i < m; i++) {
+	      // current row
+	      var row = matrix._data[i];
+	      // sum
+	      var sum = 0;
+	      // loop matrix columns
+	      for (var j = 0; j < n; j++) {
+	        // multiply & accumulate
+	        sum = math.add(sum, math.multiply(row[j], get(j)));
+	      }
+	      result[i] = sum;
+	    }
+	    // check we need to squeeze the result into a scalar
+	    if (m === 1)
+	      return result[0];
+	    // return matrix
+	    return new DenseMatrix({
+	      data: result,
+	      size: [m]
+	    });
+	  };
+	  
+	  var _multiplyMatrixMatrix = function (matrix, m, n, c, get) {
+	    // result
+	    var result = [];
+	    // loop matrix rows
+	    for (var i = 0; i < m; i++) {
+	      // current row
+	      var row = matrix._data[i];
+	      // initialize row array
+	      result[i] = [];
+	      // loop other matrix columns
+	      for (var j = 0; j < c; j++) {
+	        // sum
+	        var sum = 0;
+	        // loop matrix columns
+	        for (var x = 0; x < n; x++) {
+	          // multiply & accumulate
+	          sum = math.add(sum, math.multiply(row[x], get(x, j)));
+	        }
+	        result[i][j] = sum;
+	      }
+	    }
+	    // check we need to squeeze the result into a scalar
+	    if (m === 1 && c === 1)
+	      return result[0][0];
+	    // return matrix
+	    return new DenseMatrix({
+	      data: result,
+	      size: [m, c]
+	    });
+	  };
+	  
+	  /**
+	   * Preprocess data, which can be an Array or DenseMatrix with nested Arrays and
+	   * Matrices. Replaces all nested Matrices with Arrays
+	   * @param {Array} data
+	   * @return {Array} data
+	   */
+	  function preprocess(data) {
+	    for (var i = 0, ii = data.length; i < ii; i++) {
+	      var elem = data[i];
+	      if (isArray(elem)) {
+	        data[i] = preprocess(elem);
+	      }
+	      else if (elem instanceof math.type.Matrix) {
+	        data[i] = preprocess(elem.valueOf());
+	      }
+	    }
+
+	    return data;
+	  }
+
+	  // exports
+	  return DenseMatrix;
+	};
+
+
+/***/ },
+/* 18 */
+/***/ function(module, exports, __webpack_require__) {
+
+	'use strict';
+
+	exports.ArrayNode = __webpack_require__(176);
+	exports.AssignmentNode = __webpack_require__(177);
+	exports.BlockNode = __webpack_require__(178);
+	exports.ConditionalNode = __webpack_require__(179);
+	exports.ConstantNode = __webpack_require__(180);
+	exports.IndexNode = __webpack_require__(181);
+	exports.FunctionAssignmentNode = __webpack_require__(182);
+	exports.FunctionNode = __webpack_require__(183);
+	exports.Node = __webpack_require__(184);
+	exports.OperatorNode = __webpack_require__(185);
+	exports.RangeNode = __webpack_require__(186);
+	exports.SymbolNode = __webpack_require__(187);
+	exports.UpdateNode = __webpack_require__(188);
+
+
+/***/ },
+/* 19 */
+/***/ function(module, exports, __webpack_require__) {
+
+	'use strict';
+
+	var util = __webpack_require__(174),
+
+	    ArgumentsError = __webpack_require__(170),
 
 	    isString = util.string.isString,
 	    isArray = Array.isArray,
-	    type = util.types.type,
-
-	    // types
-	    Complex = __webpack_require__(7),
-	    Matrix = __webpack_require__(10),
-	    Unit = __webpack_require__(11),
-	    collection = __webpack_require__(14),
 
 	    // scope and nodes
-	    ArrayNode = __webpack_require__(172),
-	    AssignmentNode = __webpack_require__(173),
-	    BlockNode = __webpack_require__(174),
-	    ConditionalNode = __webpack_require__(175),
-	    ConstantNode = __webpack_require__(176),
-	    FunctionAssignmentNode = __webpack_require__(178),
-	    IndexNode = __webpack_require__(177),
-	    OperatorNode = __webpack_require__(181),
-	    FunctionNode = __webpack_require__(179),
-	    RangeNode = __webpack_require__(182),
-	    SymbolNode = __webpack_require__(183),
-	    UpdateNode = __webpack_require__(184);
-
-	/**
-	 * Parse an expression. Returns a node tree, which can be evaluated by
-	 * invoking node.eval();
-	 *
-	 * Syntax:
-	 *
-	 *     parse(expr)
-	 *     parse(expr, options)
-	 *     parse([expr1, expr2, expr3, ...])
-	 *     parse([expr1, expr2, expr3, ...], options)
-	 *
-	 * Example:
-	 *
-	 *     var node = parse('sqrt(3^2 + 4^2)');
-	 *     node.compile(math).eval(); // 5
-	 *
-	 *     var scope = {a:3, b:4}
-	 *     var node = parse('a * b'); // 12
-	 *     var code = node.compile(math);
-	 *     code.eval(scope); // 12
-	 *     scope.a = 5;
-	 *     code.eval(scope); // 20
-	 *
-	 *     var nodes = math.parse(['a = 3', 'b = 4', 'a * b']);
-	 *     nodes[2].compile(math).eval(); // 12
-	 *
-	 * @param {String | String[] | Matrix} expr
-	 * @param {{nodes: Object<String, Node>}} [options]  Available options:
-	 *                                                   - `nodes` a set of custom nodes
-	 * @return {Node | Node[]} node
-	 * @throws {Error}
-	 */
-	function parse (expr, options) {
-	  if (arguments.length != 1 && arguments.length != 2) {
-	    throw new ArgumentsError('parse', arguments.length, 1, 2);
-	  }
-
-	  // pass extra nodes
-	  extra_nodes = (options && options.nodes) ? options.nodes : {};
-
-	  if (isString(expr)) {
-	    // parse a single expression
-	    expression = expr;
-	    return parseStart();
-	  }
-	  else if (isArray(expr) || expr instanceof Matrix) {
-	    // parse an array or matrix with expressions
-	    return collection.deepMap(expr, function (elem) {
-	      if (!isString(elem)) throw new TypeError('String expected');
-
-	      expression = elem;
+	    ArrayNode = __webpack_require__(176),
+	    AssignmentNode = __webpack_require__(177),
+	    BlockNode = __webpack_require__(178),
+	    ConditionalNode = __webpack_require__(179),
+	    ConstantNode = __webpack_require__(180),
+	    FunctionAssignmentNode = __webpack_require__(182),
+	    IndexNode = __webpack_require__(181),
+	    OperatorNode = __webpack_require__(185),
+	    FunctionNode = __webpack_require__(183),
+	    RangeNode = __webpack_require__(186),
+	    SymbolNode = __webpack_require__(187),
+	    UpdateNode = __webpack_require__(188);
+
+	module.exports = function (math) {
+
+	  // types
+	  var Matrix = math.type.Matrix,
+	      collection = math.collection;
+	    
+	  /**
+	   * Parse an expression. Returns a node tree, which can be evaluated by
+	   * invoking node.eval();
+	   *
+	   * Syntax:
+	   *
+	   *     parse(expr)
+	   *     parse(expr, options)
+	   *     parse([expr1, expr2, expr3, ...])
+	   *     parse([expr1, expr2, expr3, ...], options)
+	   *
+	   * Example:
+	   *
+	   *     var node = parse('sqrt(3^2 + 4^2)');
+	   *     node.compile(math).eval(); // 5
+	   *
+	   *     var scope = {a:3, b:4}
+	   *     var node = parse('a * b'); // 12
+	   *     var code = node.compile(math);
+	   *     code.eval(scope); // 12
+	   *     scope.a = 5;
+	   *     code.eval(scope); // 20
+	   *
+	   *     var nodes = math.parse(['a = 3', 'b = 4', 'a * b']);
+	   *     nodes[2].compile(math).eval(); // 12
+	   *
+	   * @param {String | String[] | Matrix} expr
+	   * @param {{nodes: Object<String, Node>}} [options]  Available options:
+	   *                                                   - `nodes` a set of custom nodes
+	   * @return {Node | Node[]} node
+	   * @throws {Error}
+	   */
+	  function parse (expr, options) {
+	    if (arguments.length != 1 && arguments.length != 2) {
+	      throw new ArgumentsError('parse', arguments.length, 1, 2);
+	    }
+
+	    // pass extra nodes
+	    extra_nodes = (options && options.nodes) ? options.nodes : {};
+
+	    if (isString(expr)) {
+	      // parse a single expression
+	      expression = expr;
 	      return parseStart();
-	    });
-	  }
-	  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,
-	  ';': true,
-
-	  '+': true,
-	  '-': true,
-	  '*': true,
-	  '.*': true,
-	  '/': true,
-	  './': true,
-	  '%': true,
-	  '^': true,
-	  '.^': true,
-	  '~': true,
-	  '!': true,
-	  '&': true,
-	  '|': true,
-	  '^|': true,
-	  '\'': true,
-	  '=': true,
-	  ':': true,
-	  '?': true,
-
-	  '==': true,
-	  '!=': true,
-	  '<': true,
-	  '>': true,
-	  '<=': true,
-	  '>=': true,
-
-	  '<<': true,
-	  '>>': true,
-	  '>>>': true
-	};
-
-	// map with all named delimiters
-	var NAMED_DELIMITERS = {
-	  'mod': true,
-	  'to': true,
-	  'in': true,
-	  'and': true,
-	  'xor': true,
-	  'or': true,
-	  'not': true
-	};
-
-	var extra_nodes = {};             // current extra nodes
-	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
-	var nesting_level = 0;            // level of nesting inside parameters, used to ignore newline characters
-	var conditional_level = null;     // when a conditional is being parsed, the level of the conditional is stored here
-
-	/**
-	 * 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);
-	  nesting_level = 0;
-	  conditional_level = null;
-	}
-
-	/**
-	 * 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);
-	}
-
-	/**
-	 * Preview the second next character from the expression.
-	 * @return {String} cNext
-	 * @private
-	 */
-	function nextNextPreview() {
-	  return expression.charAt(index + 2);
-	}
-
-	/**
-	 * 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
-	  // space, tab, and newline when inside parameters
-	  while (c == ' ' || c == '\t' || (c == '\n' && nesting_level)) {
-	    // TODO: also take '\r' carriage return as newline? Or does that give problems on mac?
-	    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 new line character
-	  if (c == '\n' && !nesting_level) {
-	    token_type = TOKENTYPE.DELIMITER;
-	    token = c;
-	    next();
-	    return;
-	  }
-
-	  // check for delimiters consisting of 3 characters
-	  var c2 = c + nextPreview();
-	  var c3 = c2 + nextNextPreview();
-	  if (c3.length == 3 && DELIMITERS[c3]) {
-	    token_type = TOKENTYPE.DELIMITER;
-	    token = c3;
-	    next();
-	    next();
-	    next();
-	    return;
-	  }
-
-	  // check for delimiters consisting of 2 characters
-	  if (c2.length == 2 && 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 if (isArray(expr) || expr instanceof Matrix) {
+	      // parse an array or matrix with expressions
+	      return collection.deepMap(expr, function (elem) {
+	        if (!isString(elem)) throw new TypeError('String expected');
+
+	        expression = elem;
+	        return parseStart();
+	      });
 	    }
 	    else {
-	      while (isDigit(c)) {
-	        token += c;
+	      // 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,
+	    ';': true,
+
+	    '+': true,
+	    '-': true,
+	    '*': true,
+	    '.*': true,
+	    '/': true,
+	    './': true,
+	    '%': true,
+	    '^': true,
+	    '.^': true,
+	    '~': true,
+	    '!': true,
+	    '&': true,
+	    '|': true,
+	    '^|': true,
+	    '\'': true,
+	    '=': true,
+	    ':': true,
+	    '?': true,
+
+	    '==': true,
+	    '!=': true,
+	    '<': true,
+	    '>': true,
+	    '<=': true,
+	    '>=': true,
+
+	    '<<': true,
+	    '>>': true,
+	    '>>>': true
+	  };
+
+	  // map with all named delimiters
+	  var NAMED_DELIMITERS = {
+	    'mod': true,
+	    'to': true,
+	    'in': true,
+	    'and': true,
+	    'xor': true,
+	    'or': true,
+	    'not': true
+	  };
+
+	  var extra_nodes = {};             // current extra nodes
+	  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
+	  var nesting_level = 0;            // level of nesting inside parameters, used to ignore newline characters
+	  var conditional_level = null;     // when a conditional is being parsed, the level of the conditional is stored here
+
+	  /**
+	   * 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);
+	    nesting_level = 0;
+	    conditional_level = null;
+	  }
+
+	  /**
+	   * 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);
+	  }
+
+	  /**
+	   * Preview the second next character from the expression.
+	   * @return {String} cNext
+	   * @private
+	   */
+	  function nextNextPreview() {
+	    return expression.charAt(index + 2);
+	  }
+
+	  /**
+	   * 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
+	    // space, tab, and newline when inside parameters
+	    while (c == ' ' || c == '\t' || (c == '\n' && nesting_level)) {
+	      // TODO: also take '\r' carriage return as newline? Or does that give problems on mac?
+	      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 new line character
+	    if (c == '\n' && !nesting_level) {
+	      token_type = TOKENTYPE.DELIMITER;
+	      token = c;
+	      next();
+	      return;
+	    }
+
+	    // check for delimiters consisting of 3 characters
+	    var c2 = c + nextPreview();
+	    var c3 = c2 + nextNextPreview();
+	    if (c3.length == 3 && DELIMITERS[c3]) {
+	      token_type = TOKENTYPE.DELIMITER;
+	      token = c3;
+	      next();
+	      next();
+	      next();
+	      return;
+	    }
+
+	    // check for delimiters consisting of 2 characters
+	    if (c2.length == 2 && 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();
-	      }
-	    }
-	    while (isDigit(c)) {
-	      token += c;
-	      next();
-	    }
-
-	    // check for exponential notation like "2.3e-4", "1.23e50" or "2e+4"
-	    c2 = nextPreview();
-	    if ((c == 'E' || c == 'e') && (isDigit(c2) || c2 == '-' || c2 == '+')) {
-	      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;
-	      }
-
+
+	        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();
 	      }
-	    }
-
-	    return;
-	  }
-
-	  // check for variables, functions, named operators
-	  if (isAlpha(c)) {
-	    while (isAlpha(c) || isDigit(c)) {
+
+	      // check for exponential notation like "2.3e-4", "1.23e50" or "2e+4"
+	      c2 = nextPreview();
+	      if ((c == 'E' || c == 'e') && (isDigit(c2) || c2 == '-' || c2 == '+')) {
+	        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, functions, named operators
+	    if (isAlpha(c)) {
+	      while (isAlpha(c) || isDigit(c)) {
+	        token += c;
+	        next();
+	      }
+
+	      if (NAMED_DELIMITERS[token]) {
+	        token_type = TOKENTYPE.DELIMITER;
+	      }
+	      else {
+	        token_type = TOKENTYPE.SYMBOL;
+	      }
+
+	      return;
+	    }
+
+	    // something unknown is found, wrong characters -> a syntax error
+	    token_type = TOKENTYPE.UNKNOWN;
+	    while (c != '') {
 	      token += c;
 	      next();
 	    }
-
-	    if (NAMED_DELIMITERS[token]) {
-	      token_type = TOKENTYPE.DELIMITER;
-	    }
-	    else {
-	      token_type = TOKENTYPE.SYMBOL;
-	    }
-
-	    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 + '"');
-	}
-
-	/**
-	 * Get next token and skip newline tokens
-	 */
-	function getTokenSkipNewline () {
-	  do {
-	    getToken();
-	  }
-	  while (token == '\n');
-	}
-
-	/**
-	 * Open parameters.
-	 * New line characters will be ignored until closeParams() is called
-	 */
-	function openParams() {
-	  nesting_level++;
-	}
-
-	/**
-	 * Close parameters.
-	 * New line characters will no longer be ignored
-	 */
-	function closeParams() {
-	  nesting_level--;
-	}
-
-	/**
-	 * 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
-	 * @return {Node} node
-	 * @private
-	 */
-	function parseStart () {
-	  // get the first character in expression
-	  first();
-
-	  getToken();
-
-	  var node = parseBlock();
-
-	  // 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('Unexpected 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.
-	 * @return {Node} node
-	 * @private
-	 */
-	function parseBlock () {
-	  var node;
-	  var blocks = [];
-	  var visible;
-
-	  if (token == '') {
-	    // empty expression
-	    return new ConstantNode('undefined', 'undefined');
-	  }
-
-	  if (token != '\n' && token != ';') {
-	    node = parseFunctionAssignment();
-	  }
-
-	  // TODO: simplify this loop
-	  while (token == '\n' || token == ';') {
-	    if (blocks.length == 0 && node) {
-	      visible = (token != ';');
-	      blocks.push({
-	        node: node,
-	        visible: visible
-	      });
-	    }
-
-	    getToken();
-	    if (token != '\n' && token != ';' && token != '') {
+	    throw createSyntaxError('Syntax error in part "' + token + '"');
+	  }
+
+	  /**
+	   * Get next token and skip newline tokens
+	   */
+	  function getTokenSkipNewline () {
+	    do {
+	      getToken();
+	    }
+	    while (token == '\n');
+	  }
+
+	  /**
+	   * Open parameters.
+	   * New line characters will be ignored until closeParams() is called
+	   */
+	  function openParams() {
+	    nesting_level++;
+	  }
+
+	  /**
+	   * Close parameters.
+	   * New line characters will no longer be ignored
+	   */
+	  function closeParams() {
+	    nesting_level--;
+	  }
+
+	  /**
+	   * 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
+	   * @return {Node} node
+	   * @private
+	   */
+	  function parseStart () {
+	    // get the first character in expression
+	    first();
+
+	    getToken();
+
+	    var node = parseBlock();
+
+	    // 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('Unexpected 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.
+	   * @return {Node} node
+	   * @private
+	   */
+	  function parseBlock () {
+	    var node;
+	    var blocks = [];
+	    var visible;
+
+	    if (token == '') {
+	      // empty expression
+	      return new ConstantNode('undefined', 'undefined');
+	    }
+
+	    if (token != '\n' && token != ';') {
 	      node = parseFunctionAssignment();
-
-	      visible = (token != ';');
-	      blocks.push({
-	        node: node,
-	        visible: visible
-	      });
-	    }
-	  }
-
-	  if (blocks.length > 0) {
-	    return new BlockNode(blocks);
-	  }
-	  else {
-	    return node;
-	  }
-	}
-
-	/**
-	 * Parse a function assignment like "function f(a,b) = a*b"
-	 * @return {Node} node
-	 * @private
-	 */
-	function parseFunctionAssignment () {
-	  // TODO: function assignment using keyword 'function' is deprecated since version 0.18.0, cleanup some day
-	  if (token_type == TOKENTYPE.SYMBOL && token == 'function') {
-	    throw createSyntaxError('Deprecated keyword "function". ' +
-	        'Functions can now be assigned without it, like "f(x) = x^2".');
-	  }
-
-	  return parseAssignment();
-	}
-
-	/**
-	 * 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]"
-	 * @return {Node} node
-	 * @private
-	 */
-	function parseAssignment () {
-	  var name, args, expr, valid;
-
-	  var node = parseConditional();
-
-	  if (token == '=') {
-	    if (node instanceof SymbolNode) {
-	      // parse a variable assignment like 'a = 2/3'
-	      name = node.name;
-	      getTokenSkipNewline();
-	      expr = parseAssignment();
-	      return new AssignmentNode(name, expr);
-	    }
-	    else if (node instanceof IndexNode) {
-	      // parse a matrix subset assignment like 'A[1,2] = 4'
-	      getTokenSkipNewline();
-	      expr = parseAssignment();
-	      return new UpdateNode(node, expr);
-	    }
-	    else if (node instanceof FunctionNode) {
-	      // parse function assignment like 'f(x) = x^2'
-	      valid = true;
-	      args = [];
-
-	      name = node.name;
-	      node.args.forEach(function (arg, index) {
-	        if (arg instanceof SymbolNode) {
-	          args[index] = arg.name;
-	        }
-	        else {
-	          valid = false;
-	        }
-	      });
-
-	      if (valid) {
-	        getTokenSkipNewline();
-	        expr = parseAssignment();
-	        return new FunctionAssignmentNode(name, args, expr);
-	      }
-	    }
-
-	    throw createSyntaxError('Invalid left hand side of assignment operator =');
-	  }
-
-	  return node;
-	}
-
-	/**
-	 * conditional operation
-	 *
-	 *     condition ? truePart : falsePart
-	 *
-	 * Note: conditional operator is right-associative
-	 *
-	 * @return {Node} node
-	 * @private
-	 */
-	function parseConditional () {
-	  var node = parseLogicalOr();
-
-	  while (token == '?') {
-	    // set a conditional level, the range operator will be ignored as long
-	    // as conditional_level == nesting_level.
-	    var prev = conditional_level;
-	    conditional_level = nesting_level;
-	    getTokenSkipNewline();
-
-	    var condition = node;
-	    var trueExpr = parseLogicalOr();
-
-	    if (token != ':') throw createSyntaxError('False part of conditional expression expected');
-
-	    conditional_level = null;
-	    getTokenSkipNewline();
-
-	    var falseExpr = parseConditional(); // Note: check for conditional operator again, right associativity
-
-	    node = new ConditionalNode(condition, trueExpr, falseExpr);
-
-	    // restore the previous conditional level
-	    conditional_level = prev;
-	  }
-
-	  return node;
-	}
-
-	/**
-	 * logical or, 'x or y'
-	 * @return {Node} node
-	 * @private
-	 */
-	function parseLogicalOr() {
-	  var node = parseLogicalXor();
-
-	  while (token == 'or') {
-	    getTokenSkipNewline();
-	    node = new OperatorNode('or', 'or', [node, parseLogicalXor()]);
-	  }
-
-	  return node;
-	}
-
-	/**
-	 * logical exclusive or, 'x xor y'
-	 * @return {Node} node
-	 * @private
-	 */
-	function parseLogicalXor() {
-	  var node = parseLogicalAnd();
-
-	  while (token == 'xor') {
-	    getTokenSkipNewline();
-	    node = new OperatorNode('xor', 'xor', [node, parseLogicalAnd()]);
-	  }
-
-	  return node;
-	}
-
-	/**
-	 * logical and, 'x and y'
-	 * @return {Node} node
-	 * @private
-	 */
-	function parseLogicalAnd() {
-	  var node = parseBitwiseOr();
-
-	  while (token == 'and') {
-	    getTokenSkipNewline();
-	    node = new OperatorNode('and', 'and', [node, parseBitwiseOr()]);
-	  }
-
-	  return node;
-	}
-
-	/**
-	 * bitwise or, 'x | y'
-	 * @return {Node} node
-	 * @private
-	 */
-	function parseBitwiseOr() {
-	  var node = parseBitwiseXor();
-
-	  while (token == '|') {
-	    getTokenSkipNewline();
-	    node = new OperatorNode('|', 'bitOr', [node, parseBitwiseXor()]);
-	  }
-
-	  return node;
-	}
-
-	/**
-	 * bitwise exclusive or (xor), 'x ^| y'
-	 * @return {Node} node
-	 * @private
-	 */
-	function parseBitwiseXor() {
-	  var node = parseBitwiseAnd();
-
-	  while (token == '^|') {
-	    getTokenSkipNewline();
-	    node = new OperatorNode('^|', 'bitXor', [node, parseBitwiseAnd()]);
-	  }
-
-	  return node;
-	}
-
-	/**
-	 * bitwise and, 'x & y'
-	 * @return {Node} node
-	 * @private
-	 */
-	function parseBitwiseAnd () {
-	  var node = parseRelational();
-
-	  while (token == '&') {
-	    getTokenSkipNewline();
-	    node = new OperatorNode('&', 'bitAnd', [node, parseRelational()]);
-	  }
-
-	  return node;
-	}
-
-	/**
-	 * relational operators
-	 * @return {Node} node
-	 * @private
-	 */
-	function parseRelational () {
-	  var node, operators, name, fn, params;
-
-	  node = parseShift();
-
-	  operators = {
-	    '==': 'equal',
-	    '!=': 'unequal',
-	    '<': 'smaller',
-	    '>': 'larger',
-	    '<=': 'smallerEq',
-	    '>=': 'largerEq'
-	  };
-	  while (token in operators) {
-	    name = token;
-	    fn = operators[name];
-
-	    getTokenSkipNewline();
-	    params = [node, parseShift()];
-	    node = new OperatorNode(name, fn, params);
-	  }
-
-	  return node;
-	}
-
-	/**
-	 * Bitwise left shift, bitwise right arithmetic shift, bitwise right logical shift
-	 * @return {Node} node
-	 * @private
-	 */
-	function parseShift () {
-	  var node, operators, name, fn, params;
-
-	  node = parseConversion();
-
-	  operators = {
-	    '<<' : 'leftShift',
-	    '>>' : 'rightArithShift',
-	    '>>>' : 'rightLogShift'
-	  };
-
-	  while (token in operators) {
-	    name = token;
-	    fn = operators[name];
-
-	    getTokenSkipNewline();
-	    params = [node, parseConversion()];
-	    node = new OperatorNode(name, fn, params);
-	  }
-
-	  return node;
-	}
-
-	/**
-	 * conversion operators 'to' and 'in'
-	 * @return {Node} node
-	 * @private
-	 */
-	function parseConversion () {
-	  var node, operators, name, fn, params;
-
-	  node = parseRange();
-
-	  operators = {
-	    'to' : 'to',
-	    'in' : 'to'   // alias of 'to'
-	  };
-
-	  while (token in operators) {
-	    name = token;
-	    fn = operators[name];
-
-	    getTokenSkipNewline();
-	    params = [node, parseRange()];
-	    node = new OperatorNode(name, fn, params);
-	  }
-
-	  return node;
-	}
-
-	/**
-	 * parse range, "start:end", "start:step:end", ":", "start:", ":end", etc
-	 * @return {Node} node
-	 * @private
-	 */
-	function parseRange () {
-	  var node, params = [];
-
-	  if (token == ':') {
-	    // implicit start=1 (one-based)
-	    node = new ConstantNode('1', 'number');
-	  }
-	  else {
-	    // explicit start
-	    node = parseAddSubtract();
-	  }
-
-	  if (token == ':' && (conditional_level !== nesting_level)) {
-	    // we ignore the range operator when a conditional operator is being processed on the same level
-	    params.push(node);
-
-	    // parse step and end
-	    while (token == ':' && params.length < 3) {
-	      getTokenSkipNewline();
-
-	      if (token == ')' || token == ']' || token == ',' || token == '') {
-	        // implicit end
-	        params.push(new SymbolNode('end'));
-	      }
-	      else {
-	        // explicit end
-	        params.push(parseAddSubtract());
-	      }
-	    }
-
-	    if (params.length == 3) {
-	      // params = [start, step, end]
-	      node = new RangeNode(params[0], params[2], params[1]); // start, end, step
-	    }
-	    else { // length == 2
-	      // params = [start, end]
-	      node = new RangeNode(params[0], params[1]); // start, end
-	    }
-	  }
-
-	  return node;
-	}
-
-	/**
-	 * add or subtract
-	 * @return {Node} node
-	 * @private
-	 */
-	function parseAddSubtract ()  {
-	  var node, operators, name, fn, params;
-
-	  node = parseMultiplyDivide();
-
-	  operators = {
-	    '+': 'add',
-	    '-': 'subtract'
-	  };
-	  while (token in operators) {
-	    name = token;
-	    fn = operators[name];
-
-	    getTokenSkipNewline();
-	    params = [node, parseMultiplyDivide()];
-	    node = new OperatorNode(name, fn, params);
-	  }
-
-	  return node;
-	}
-
-	/**
-	 * multiply, divide, modulus
-	 * @return {Node} node
-	 * @private
-	 */
-	function parseMultiplyDivide () {
-	  var node, operators, name, fn, params;
-
-	  node = parseUnary();
-
-	  operators = {
-	    '*': 'multiply',
-	    '.*': 'dotMultiply',
-	    '/': 'divide',
-	    './': 'dotDivide',
-	    '%': 'mod',
-	    'mod': 'mod'
-	  };
-
-	  if (token in operators) {
-	    while (token in operators) {
-	      name = token;
-	      fn = operators[name];
-
-	      getTokenSkipNewline();
-	      params = [node, parseUnary()];
-	      node = new OperatorNode(name, fn, params);
-	    }
-	  }
-
-	  // parse implicit multiplication
-	  if ((token_type == TOKENTYPE.SYMBOL) ||
-	      (token == 'in' && (node instanceof ConstantNode)) ||
-	      (token_type == TOKENTYPE.NUMBER && !(node instanceof ConstantNode)) ||
-	      (token == '(' || token == '[')) {
-	    // symbol:      implicit multiplication like '2a', '(2+3)a', 'a b'
-	    // number:      implicit multiplication like '(2+3)2'
-	    //              Note: we don't allow implicit multiplication between numbers,
-	    //              like '2 3'. I'm not sure whether that is a good idea.
-	    // parenthesis: implicit multiplication like '2(3+4)', '(3+4)(1+2)', '2[1,2,3]'
-	    node = new OperatorNode('*', 'multiply', [node, parseMultiplyDivide()]);
-	  }
-
-	  return node;
-	}
-
-	/**
-	 * Unary plus and minus, and logical and bitwise not
-	 * @return {Node} node
-	 * @private
-	 */
-	function parseUnary () {
-	  var name, params;
-	  var fn = {
-	    '-': 'unaryMinus',
-	    '+': 'unaryPlus',
-	    '~': 'bitNot',
-	    'not': 'not'
-	  }[token];
-
-	  if (fn) {
-	    name = token;
-
-	    getTokenSkipNewline();
-	    params = [parseUnary()];
-
-	    return new OperatorNode(name, fn, params);
-	  }
-
-	  return parsePow();
-	}
-
-	/**
-	 * power
-	 * Note: power operator is right associative
-	 * @return {Node} node
-	 * @private
-	 */
-	function parsePow () {
-	  var node, name, fn, params;
-
-	  node = parseLeftHandOperators();
-
-	  if (token == '^' || token == '.^') {
-	    name = token;
-	    fn = (name == '^') ? 'pow' : 'dotPow';
-
-	    getTokenSkipNewline();
-	    params = [node, parseUnary()]; // Go back to unary, we can have '2^-3'
-	    node = new OperatorNode(name, fn, params);
-	  }
-
-	  return node;
-	}
-
-	/**
-	 * Left hand operators: factorial x!, transpose x'
-	 * @return {Node} node
-	 * @private
-	 */
-	function parseLeftHandOperators ()  {
-	  var node, operators, name, fn, params;
-
-	  node = parseCustomNodes();
-
-	  operators = {
-	    '!': 'factorial',
-	    '\'': 'transpose'
-	  };
-
-	  while (token in operators) {
-	    name = token;
-	    fn = operators[name];
-
-	    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 passed as second argument of the parse function.
-	 * - must extend math.expression.node.Node
-	 * - must contain a function _compile(defs: Object) : String
-	 * - must contain a function find(filter: Object) : Node[]
-	 * - must contain a function toString() : String
-	 * - the constructor is called with a single argument containing all parameters
-	 *
-	 * For example:
-	 *
-	 *     nodes = {
-	 *       'plot': PlotHandler
-	 *     };
-	 *
-	 * The constructor of the handler is called as:
-	 *
-	 *     node = new PlotHandler(params);
-	 *
-	 * The handler will be invoked when evaluating an expression like:
-	 *
-	 *     node = math.parse('plot(sin(x), x)', nodes);
-	 *
-	 * @return {Node} node
-	 * @private
-	 */
-	function parseCustomNodes () {
-	  var params = [], handler;
-
-	  if (token_type == TOKENTYPE.SYMBOL && extra_nodes[token]) {
-	    handler = extra_nodes[token];
-
-	    getToken();
-
-	    // parse parameters
-	    if (token == '(') {
-	      params = [];
-
-	      openParams();
-	      getToken();
-
-	      if (token != ')') {
-	        params.push(parseConditional());
-
-	        // parse a list with parameters
-	        while (token == ',') {
-	          getToken();
-	          params.push(parseConditional());
-	        }
-	      }
-
-	      if (token != ')') {
-	        throw createSyntaxError('Parenthesis ) expected');
-	      }
-	      closeParams();
-	      getToken();
-	    }
-
-	    // create a new node handler
-	    //noinspection JSValidateTypes
-	    return new handler(params);
-	  }
-
-	  return parseSymbol();
-	}
-
-	/**
-	 * parse symbols: functions, variables, constants, units
-	 * @return {Node} node
-	 * @private
-	 */
-	function parseSymbol () {
-	  var node, name;
-
-	  if (token_type == TOKENTYPE.SYMBOL ||
-	      (token_type == TOKENTYPE.DELIMITER && token in NAMED_DELIMITERS)) {
-	    name = token;
-
-	    getToken();
-
-	    // parse function parameters and matrix index
-	    node = parseFunctions(name);
-	    node = parseIndex(node);
-	    return node;
-	  }
-
-	  return parseString();
-	}
-
-	/**
-	 * parse a function call like fn(a, b, c)
-	 * @param {string} name    Function name
-	 * @return {FunctionNode | SymbolNode} node
-	 * @private
-	 */
-	function parseFunctions (name) {
-	  var params;
-
-	  if (token == '(') {
-	    params = [];
-
-	    openParams();
-	    getToken();
-
-	    if (token != ')') {
-	      params.push(parseConditional());
-
-	      // parse a list with parameters
-	      while (token == ',') {
-	        getToken();
-	        params.push(parseConditional());
-	      }
-	    }
-
-	    if (token != ')') {
-	      throw createSyntaxError('Parenthesis ) expected');
-	    }
-	    closeParams();
-	    getToken();
-
-	    return new FunctionNode(name, params);
-	  }
-
-	  return new SymbolNode(name);
-	}
-
-	/**
-	 * parse index parameters, enclosed in square brackets [...], for example A[2,3]
-	 * @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 parseIndex (node) {
-	  var params;
-
-	  while (token == '[') {
-	    params = [];
-
-	    openParams();
-	    getToken();
-
-	    if (token != ']') {
-	      params.push(parseConditional());
-
-	      // parse a list with parameters
-	      while (token == ',') {
-	        getToken();
-	        params.push(parseConditional());
-	      }
-	    }
-
-	    if (token != ']') {
-	      throw createSyntaxError('Parenthesis ] expected');
-	    }
-	    closeParams();
-	    getToken();
-
-	    node = new IndexNode(node, params);
-	  }
-
-	  return node;
-	}
-
-	/**
-	 * parse a string.
-	 * A string is enclosed by double quotes
-	 * @return {Node} node
-	 * @private
-	 */
-	function parseString () {
-	  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, 'string');
-
-	    // parse index parameters
-	    node = parseIndex(node);
-
-	    return node;
-	  }
-
-	  return parseMatrix();
-	}
-
-	/**
-	 * parse the matrix
-	 * @return {Node} node
-	 * @private
-	 */
-	function parseMatrix () {
-	  var array, params, rows, cols;
-
-	  if (token == '[') {
-	    // matrix [...]
-	    openParams();
-	    getToken();
-
-	    if (token != ']') {
-	      // this is a non-empty matrix
-	      var row = parseRow();
-
-	      if (token == ';') {
-	        // 2 dimensional array
-	        rows = 1;
-	        params = [row];
-
-	        // the rows of the matrix are separated by dot-comma's
-	        while (token == ';') {
-	          getToken();
-
-	          params[rows] = parseRow();
-	          rows++;
-	        }
-
-	        if (token != ']') {
-	          throw createSyntaxError('End of matrix ] expected');
-	        }
-	        closeParams();
-	        getToken();
-
-	        // check if the number of columns matches in all rows
-	        cols = params[0].nodes.length;
-	        for (var r = 1; r < rows; r++) {
-	          if (params[r].nodes.length != cols) {
-	            throw createError('Column dimensions mismatch ' +
-	                '(' + params[r].nodes.length + ' != ' + cols + ')');
-	          }
-	        }
-
-	        array = new ArrayNode(params);
-	      }
-	      else {
-	        // 1 dimensional vector
-	        if (token != ']') {
-	          throw createSyntaxError('End of matrix ] expected');
-	        }
-	        closeParams();
-	        getToken();
-
-	        array = row;
-	      }
-	    }
-	    else {
-	      // this is an empty matrix "[ ]"
-	      closeParams();
-	      getToken();
-	      array = new ArrayNode([]);
-	    }
-
-	    return array;
-	  }
-
-	  return parseNumber();
-	}
-
-	/**
-	 * Parse a single comma-separated row from a matrix, like 'a, b, c'
-	 * @return {ArrayNode} node
-	 */
-	function parseRow () {
-	  var params = [parseAssignment()];
-	  var len = 1;
-
-	  while (token == ',') {
-	    getToken();
-
-	    // parse expression
-	    params[len] = parseAssignment();
-	    len++;
-	  }
-
-	  return new ArrayNode(params);
-	}
-
-	/**
-	 * parse a number
-	 * @return {Node} node
-	 * @private
-	 */
-	function parseNumber () {
-	  var number;
-
-	  if (token_type == TOKENTYPE.NUMBER) {
-	    // this is a number
-	    number = token;
-	    getToken();
-
-	    return new ConstantNode(number, 'number');
-	  }
-
-	  return parseParentheses();
-	}
-
-	/**
-	 * parentheses
-	 * @return {Node} node
-	 * @private
-	 */
-	function parseParentheses () {
-	  var node;
-
-	  // check if it is a parenthesized expression
-	  if (token == '(') {
-	    // parentheses (...)
-	    openParams();
-	    getToken();
-
-	    node = parseAssignment(); // start again
-
-	    if (token != ')') {
-	      throw createSyntaxError('Parenthesis ) expected');
-	    }
-	    closeParams();
-	    getToken();
-
-	    return node;
-	  }
-
-	  return parseEnd();
-	}
-
-	/**
-	 * Evaluated when the expression is not yet ended but expected to end
-	 * @return {Node} res
-	 * @private
-	 */
-	function parseEnd () {
-	  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
-	 */
-	/* TODO: implement keeping track on the row number
-	function row () {
-	  return null;
-	}
-	*/
-
-	/**
-	 * 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;
-	}
-
-	/**
-	 * Create an error
-	 * @param {String} message
-	 * @return {SyntaxError} instantiated error
-	 * @private
-	 */
-	function createSyntaxError (message) {
-	  var c = col();
-	  var error = new SyntaxError(message + ' (char ' + c + ')');
-	  error['char'] = c;
-
-	  return error;
-	}
-
-	/**
-	 * Create an error
-	 * @param {String} message
-	 * @return {Error} instantiated error
-	 * @private
-	 */
-	function createError (message) {
-	  var c = col();
-	  var error = new Error(message + ' (char ' + c + ')');
-	  error['char'] = c;
-
-	  return error;
-	}
-
-	module.exports = parse;
-
+	    }
+
+	    // TODO: simplify this loop
+	    while (token == '\n' || token == ';') {
+	      if (blocks.length == 0 && node) {
+	        visible = (token != ';');
+	        blocks.push({
+	          node: node,
+	          visible: visible
+	        });
+	      }
+
+	      getToken();
+	      if (token != '\n' && token != ';' && token != '') {
+	        node = parseFunctionAssignment();
+
+	        visible = (token != ';');
+	        blocks.push({
+	          node: node,
+	          visible: visible
+	        });
+	      }
+	    }
+
+	    if (blocks.length > 0) {
+	      return new BlockNode(blocks);
+	    }
+	    else {
+	      return node;
+	    }
+	  }
+
+	  /**
+	   * Parse a function assignment like "function f(a,b) = a*b"
+	   * @return {Node} node
+	   * @private
+	   */
+	  function parseFunctionAssignment () {
+	    // TODO: function assignment using keyword 'function' is deprecated since version 0.18.0, cleanup some day
+	    if (token_type == TOKENTYPE.SYMBOL && token == 'function') {
+	      throw createSyntaxError('Deprecated keyword "function". ' +
+	          'Functions can now be assigned without it, like "f(x) = x^2".');
+	    }
+
+	    return parseAssignment();
+	  }
+
+	  /**
+	   * 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]"
+	   * @return {Node} node
+	   * @private
+	   */
+	  function parseAssignment () {
+	    var name, args, expr, valid;
+
+	    var node = parseConditional();
+
+	    if (token == '=') {
+	      if (node instanceof SymbolNode) {
+	        // parse a variable assignment like 'a = 2/3'
+	        name = node.name;
+	        getTokenSkipNewline();
+	        expr = parseAssignment();
+	        return new AssignmentNode(name, expr);
+	      }
+	      else if (node instanceof IndexNode) {
+	        // parse a matrix subset assignment like 'A[1,2] = 4'
+	        getTokenSkipNewline();
+	        expr = parseAssignment();
+	        return new UpdateNode(node, expr);
+	      }
+	      else if (node instanceof FunctionNode) {
+	        // parse function assignment like 'f(x) = x^2'
+	        valid = true;
+	        args = [];
+
+	        name = node.name;
+	        node.args.forEach(function (arg, index) {
+	          if (arg instanceof SymbolNode) {
+	            args[index] = arg.name;
+	          }
+	          else {
+	            valid = false;
+	          }
+	        });
+
+	        if (valid) {
+	          getTokenSkipNewline();
+	          expr = parseAssignment();
+	          return new FunctionAssignmentNode(name, args, expr);
+	        }
+	      }
+
+	      throw createSyntaxError('Invalid left hand side of assignment operator =');
+	    }
+
+	    return node;
+	  }
+
+	  /**
+	   * conditional operation
+	   *
+	   *     condition ? truePart : falsePart
+	   *
+	   * Note: conditional operator is right-associative
+	   *
+	   * @return {Node} node
+	   * @private
+	   */
+	  function parseConditional () {
+	    var node = parseLogicalOr();
+
+	    while (token == '?') {
+	      // set a conditional level, the range operator will be ignored as long
+	      // as conditional_level == nesting_level.
+	      var prev = conditional_level;
+	      conditional_level = nesting_level;
+	      getTokenSkipNewline();
+
+	      var condition = node;
+	      var trueExpr = parseLogicalOr();
+
+	      if (token != ':') throw createSyntaxError('False part of conditional expression expected');
+
+	      conditional_level = null;
+	      getTokenSkipNewline();
+
+	      var falseExpr = parseConditional(); // Note: check for conditional operator again, right associativity
+
+	      node = new ConditionalNode(condition, trueExpr, falseExpr);
+
+	      // restore the previous conditional level
+	      conditional_level = prev;
+	    }
+
+	    return node;
+	  }
+
+	  /**
+	   * logical or, 'x or y'
+	   * @return {Node} node
+	   * @private
+	   */
+	  function parseLogicalOr() {
+	    var node = parseLogicalXor();
+
+	    while (token == 'or') {
+	      getTokenSkipNewline();
+	      node = new OperatorNode('or', 'or', [node, parseLogicalXor()]);
+	    }
+
+	    return node;
+	  }
+
+	  /**
+	   * logical exclusive or, 'x xor y'
+	   * @return {Node} node
+	   * @private
+	   */
+	  function parseLogicalXor() {
+	    var node = parseLogicalAnd();
+
+	    while (token == 'xor') {
+	      getTokenSkipNewline();
+	      node = new OperatorNode('xor', 'xor', [node, parseLogicalAnd()]);
+	    }
+
+	    return node;
+	  }
+
+	  /**
+	   * logical and, 'x and y'
+	   * @return {Node} node
+	   * @private
+	   */
+	  function parseLogicalAnd() {
+	    var node = parseBitwiseOr();
+
+	    while (token == 'and') {
+	      getTokenSkipNewline();
+	      node = new OperatorNode('and', 'and', [node, parseBitwiseOr()]);
+	    }
+
+	    return node;
+	  }
+
+	  /**
+	   * bitwise or, 'x | y'
+	   * @return {Node} node
+	   * @private
+	   */
+	  function parseBitwiseOr() {
+	    var node = parseBitwiseXor();
+
+	    while (token == '|') {
+	      getTokenSkipNewline();
+	      node = new OperatorNode('|', 'bitOr', [node, parseBitwiseXor()]);
+	    }
+
+	    return node;
+	  }
+
+	  /**
+	   * bitwise exclusive or (xor), 'x ^| y'
+	   * @return {Node} node
+	   * @private
+	   */
+	  function parseBitwiseXor() {
+	    var node = parseBitwiseAnd();
+
+	    while (token == '^|') {
+	      getTokenSkipNewline();
+	      node = new OperatorNode('^|', 'bitXor', [node, parseBitwiseAnd()]);
+	    }
+
+	    return node;
+	  }
+
+	  /**
+	   * bitwise and, 'x & y'
+	   * @return {Node} node
+	   * @private
+	   */
+	  function parseBitwiseAnd () {
+	    var node = parseRelational();
+
+	    while (token == '&') {
+	      getTokenSkipNewline();
+	      node = new OperatorNode('&', 'bitAnd', [node, parseRelational()]);
+	    }
+
+	    return node;
+	  }
+
+	  /**
+	   * relational operators
+	   * @return {Node} node
+	   * @private
+	   */
+	  function parseRelational () {
+	    var node, operators, name, fn, params;
+
+	    node = parseShift();
+
+	    operators = {
+	      '==': 'equal',
+	      '!=': 'unequal',
+	      '<': 'smaller',
+	      '>': 'larger',
+	      '<=': 'smallerEq',
+	      '>=': 'largerEq'
+	    };
+	    while (token in operators) {
+	      name = token;
+	      fn = operators[name];
+
+	      getTokenSkipNewline();
+	      params = [node, parseShift()];
+	      node = new OperatorNode(name, fn, params);
+	    }
+
+	    return node;
+	  }
+
+	  /**
+	   * Bitwise left shift, bitwise right arithmetic shift, bitwise right logical shift
+	   * @return {Node} node
+	   * @private
+	   */
+	  function parseShift () {
+	    var node, operators, name, fn, params;
+
+	    node = parseConversion();
+
+	    operators = {
+	      '<<' : 'leftShift',
+	      '>>' : 'rightArithShift',
+	      '>>>' : 'rightLogShift'
+	    };
+
+	    while (token in operators) {
+	      name = token;
+	      fn = operators[name];
+
+	      getTokenSkipNewline();
+	      params = [node, parseConversion()];
+	      node = new OperatorNode(name, fn, params);
+	    }
+
+	    return node;
+	  }
+
+	  /**
+	   * conversion operators 'to' and 'in'
+	   * @return {Node} node
+	   * @private
+	   */
+	  function parseConversion () {
+	    var node, operators, name, fn, params;
+
+	    node = parseRange();
+
+	    operators = {
+	      'to' : 'to',
+	      'in' : 'to'   // alias of 'to'
+	    };
+
+	    while (token in operators) {
+	      name = token;
+	      fn = operators[name];
+
+	      getTokenSkipNewline();
+	      params = [node, parseRange()];
+	      node = new OperatorNode(name, fn, params);
+	    }
+
+	    return node;
+	  }
+
+	  /**
+	   * parse range, "start:end", "start:step:end", ":", "start:", ":end", etc
+	   * @return {Node} node
+	   * @private
+	   */
+	  function parseRange () {
+	    var node, params = [];
+
+	    if (token == ':') {
+	      // implicit start=1 (one-based)
+	      node = new ConstantNode('1', 'number');
+	    }
+	    else {
+	      // explicit start
+	      node = parseAddSubtract();
+	    }
+
+	    if (token == ':' && (conditional_level !== nesting_level)) {
+	      // we ignore the range operator when a conditional operator is being processed on the same level
+	      params.push(node);
+
+	      // parse step and end
+	      while (token == ':' && params.length < 3) {
+	        getTokenSkipNewline();
+
+	        if (token == ')' || token == ']' || token == ',' || token == '') {
+	          // implicit end
+	          params.push(new SymbolNode('end'));
+	        }
+	        else {
+	          // explicit end
+	          params.push(parseAddSubtract());
+	        }
+	      }
+
+	      if (params.length == 3) {
+	        // params = [start, step, end]
+	        node = new RangeNode(params[0], params[2], params[1]); // start, end, step
+	      }
+	      else { // length == 2
+	        // params = [start, end]
+	        node = new RangeNode(params[0], params[1]); // start, end
+	      }
+	    }
+
+	    return node;
+	  }
+
+	  /**
+	   * add or subtract
+	   * @return {Node} node
+	   * @private
+	   */
+	  function parseAddSubtract ()  {
+	    var node, operators, name, fn, params;
+
+	    node = parseMultiplyDivide();
+
+	    operators = {
+	      '+': 'add',
+	      '-': 'subtract'
+	    };
+	    while (token in operators) {
+	      name = token;
+	      fn = operators[name];
+
+	      getTokenSkipNewline();
+	      params = [node, parseMultiplyDivide()];
+	      node = new OperatorNode(name, fn, params);
+	    }
+
+	    return node;
+	  }
+
+	  /**
+	   * multiply, divide, modulus
+	   * @return {Node} node
+	   * @private
+	   */
+	  function parseMultiplyDivide () {
+	    var node, operators, name, fn, params;
+
+	    node = parseUnary();
+
+	    operators = {
+	      '*': 'multiply',
+	      '.*': 'dotMultiply',
+	      '/': 'divide',
+	      './': 'dotDivide',
+	      '%': 'mod',
+	      'mod': 'mod'
+	    };
+
+	    if (token in operators) {
+	      while (token in operators) {
+	        name = token;
+	        fn = operators[name];
+
+	        getTokenSkipNewline();
+	        params = [node, parseUnary()];
+	        node = new OperatorNode(name, fn, params);
+	      }
+	    }
+
+	    // parse implicit multiplication
+	    if ((token_type == TOKENTYPE.SYMBOL) ||
+	        (token == 'in' && (node instanceof ConstantNode)) ||
+	        (token_type == TOKENTYPE.NUMBER && !(node instanceof ConstantNode)) ||
+	        (token == '(' || token == '[')) {
+	      // symbol:      implicit multiplication like '2a', '(2+3)a', 'a b'
+	      // number:      implicit multiplication like '(2+3)2'
+	      //              Note: we don't allow implicit multiplication between numbers,
+	      //              like '2 3'. I'm not sure whether that is a good idea.
+	      // parenthesis: implicit multiplication like '2(3+4)', '(3+4)(1+2)', '2[1,2,3]'
+	      node = new OperatorNode('*', 'multiply', [node, parseMultiplyDivide()]);
+	    }
+
+	    return node;
+	  }
+
+	  /**
+	   * Unary plus and minus, and logical and bitwise not
+	   * @return {Node} node
+	   * @private
+	   */
+	  function parseUnary () {
+	    var name, params;
+	    var fn = {
+	      '-': 'unaryMinus',
+	      '+': 'unaryPlus',
+	      '~': 'bitNot',
+	      'not': 'not'
+	    }[token];
+
+	    if (fn) {
+	      name = token;
+
+	      getTokenSkipNewline();
+	      params = [parseUnary()];
+
+	      return new OperatorNode(name, fn, params);
+	    }
+
+	    return parsePow();
+	  }
+
+	  /**
+	   * power
+	   * Note: power operator is right associative
+	   * @return {Node} node
+	   * @private
+	   */
+	  function parsePow () {
+	    var node, name, fn, params;
+
+	    node = parseLeftHandOperators();
+
+	    if (token == '^' || token == '.^') {
+	      name = token;
+	      fn = (name == '^') ? 'pow' : 'dotPow';
+
+	      getTokenSkipNewline();
+	      params = [node, parseUnary()]; // Go back to unary, we can have '2^-3'
+	      node = new OperatorNode(name, fn, params);
+	    }
+
+	    return node;
+	  }
+
+	  /**
+	   * Left hand operators: factorial x!, transpose x'
+	   * @return {Node} node
+	   * @private
+	   */
+	  function parseLeftHandOperators ()  {
+	    var node, operators, name, fn, params;
+
+	    node = parseCustomNodes();
+
+	    operators = {
+	      '!': 'factorial',
+	      '\'': 'transpose'
+	    };
+
+	    while (token in operators) {
+	      name = token;
+	      fn = operators[name];
+
+	      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 passed as second argument of the parse function.
+	   * - must extend math.expression.node.Node
+	   * - must contain a function _compile(defs: Object) : String
+	   * - must contain a function find(filter: Object) : Node[]
+	   * - must contain a function toString() : String
+	   * - the constructor is called with a single argument containing all parameters
+	   *
+	   * For example:
+	   *
+	   *     nodes = {
+	   *       'plot': PlotHandler
+	   *     };
+	   *
+	   * The constructor of the handler is called as:
+	   *
+	   *     node = new PlotHandler(params);
+	   *
+	   * The handler will be invoked when evaluating an expression like:
+	   *
+	   *     node = math.parse('plot(sin(x), x)', nodes);
+	   *
+	   * @return {Node} node
+	   * @private
+	   */
+	  function parseCustomNodes () {
+	    var params = [], handler;
+
+	    if (token_type == TOKENTYPE.SYMBOL && extra_nodes[token]) {
+	      handler = extra_nodes[token];
+
+	      getToken();
+
+	      // parse parameters
+	      if (token == '(') {
+	        params = [];
+
+	        openParams();
+	        getToken();
+
+	        if (token != ')') {
+	          params.push(parseConditional());
+
+	          // parse a list with parameters
+	          while (token == ',') {
+	            getToken();
+	            params.push(parseConditional());
+	          }
+	        }
+
+	        if (token != ')') {
+	          throw createSyntaxError('Parenthesis ) expected');
+	        }
+	        closeParams();
+	        getToken();
+	      }
+
+	      // create a new node handler
+	      //noinspection JSValidateTypes
+	      return new handler(params);
+	    }
+
+	    return parseSymbol();
+	  }
+
+	  /**
+	   * parse symbols: functions, variables, constants, units
+	   * @return {Node} node
+	   * @private
+	   */
+	  function parseSymbol () {
+	    var node, name;
+
+	    if (token_type == TOKENTYPE.SYMBOL ||
+	        (token_type == TOKENTYPE.DELIMITER && token in NAMED_DELIMITERS)) {
+	      name = token;
+
+	      getToken();
+
+	      // parse function parameters and matrix index
+	      node = parseFunctions(name);
+	      node = parseIndex(node);
+	      return node;
+	    }
+
+	    return parseString();
+	  }
+
+	  /**
+	   * parse a function call like fn(a, b, c)
+	   * @param {string} name    Function name
+	   * @return {FunctionNode | SymbolNode} node
+	   * @private
+	   */
+	  function parseFunctions (name) {
+	    var params;
+
+	    if (token == '(') {
+	      params = [];
+
+	      openParams();
+	      getToken();
+
+	      if (token != ')') {
+	        params.push(parseConditional());
+
+	        // parse a list with parameters
+	        while (token == ',') {
+	          getToken();
+	          params.push(parseConditional());
+	        }
+	      }
+
+	      if (token != ')') {
+	        throw createSyntaxError('Parenthesis ) expected');
+	      }
+	      closeParams();
+	      getToken();
+
+	      return new FunctionNode(name, params);
+	    }
+
+	    return new SymbolNode(name);
+	  }
+
+	  /**
+	   * parse index parameters, enclosed in square brackets [...], for example A[2,3]
+	   * @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 parseIndex (node) {
+	    var params;
+
+	    while (token == '[') {
+	      params = [];
+
+	      openParams();
+	      getToken();
+
+	      if (token != ']') {
+	        params.push(parseConditional());
+
+	        // parse a list with parameters
+	        while (token == ',') {
+	          getToken();
+	          params.push(parseConditional());
+	        }
+	      }
+
+	      if (token != ']') {
+	        throw createSyntaxError('Parenthesis ] expected');
+	      }
+	      closeParams();
+	      getToken();
+
+	      node = new IndexNode(node, params);
+	    }
+
+	    return node;
+	  }
+
+	  /**
+	   * parse a string.
+	   * A string is enclosed by double quotes
+	   * @return {Node} node
+	   * @private
+	   */
+	  function parseString () {
+	    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, 'string');
+
+	      // parse index parameters
+	      node = parseIndex(node);
+
+	      return node;
+	    }
+
+	    return parseMatrix();
+	  }
+
+	  /**
+	   * parse the matrix
+	   * @return {Node} node
+	   * @private
+	   */
+	  function parseMatrix () {
+	    var array, params, rows, cols;
+
+	    if (token == '[') {
+	      // matrix [...]
+	      openParams();
+	      getToken();
+
+	      if (token != ']') {
+	        // this is a non-empty matrix
+	        var row = parseRow();
+
+	        if (token == ';') {
+	          // 2 dimensional array
+	          rows = 1;
+	          params = [row];
+
+	          // the rows of the matrix are separated by dot-comma's
+	          while (token == ';') {
+	            getToken();
+
+	            params[rows] = parseRow();
+	            rows++;
+	          }
+
+	          if (token != ']') {
+	            throw createSyntaxError('End of matrix ] expected');
+	          }
+	          closeParams();
+	          getToken();
+
+	          // check if the number of columns matches in all rows
+	          cols = params[0].nodes.length;
+	          for (var r = 1; r < rows; r++) {
+	            if (params[r].nodes.length != cols) {
+	              throw createError('Column dimensions mismatch ' +
+	                  '(' + params[r].nodes.length + ' != ' + cols + ')');
+	            }
+	          }
+
+	          array = new ArrayNode(params);
+	        }
+	        else {
+	          // 1 dimensional vector
+	          if (token != ']') {
+	            throw createSyntaxError('End of matrix ] expected');
+	          }
+	          closeParams();
+	          getToken();
+
+	          array = row;
+	        }
+	      }
+	      else {
+	        // this is an empty matrix "[ ]"
+	        closeParams();
+	        getToken();
+	        array = new ArrayNode([]);
+	      }
+
+	      return array;
+	    }
+
+	    return parseNumber();
+	  }
+
+	  /**
+	   * Parse a single comma-separated row from a matrix, like 'a, b, c'
+	   * @return {ArrayNode} node
+	   */
+	  function parseRow () {
+	    var params = [parseAssignment()];
+	    var len = 1;
+
+	    while (token == ',') {
+	      getToken();
+
+	      // parse expression
+	      params[len] = parseAssignment();
+	      len++;
+	    }
+
+	    return new ArrayNode(params);
+	  }
+
+	  /**
+	   * parse a number
+	   * @return {Node} node
+	   * @private
+	   */
+	  function parseNumber () {
+	    var number;
+
+	    if (token_type == TOKENTYPE.NUMBER) {
+	      // this is a number
+	      number = token;
+	      getToken();
+
+	      return new ConstantNode(number, 'number');
+	    }
+
+	    return parseParentheses();
+	  }
+
+	  /**
+	   * parentheses
+	   * @return {Node} node
+	   * @private
+	   */
+	  function parseParentheses () {
+	    var node;
+
+	    // check if it is a parenthesized expression
+	    if (token == '(') {
+	      // parentheses (...)
+	      openParams();
+	      getToken();
+
+	      node = parseAssignment(); // start again
+
+	      if (token != ')') {
+	        throw createSyntaxError('Parenthesis ) expected');
+	      }
+	      closeParams();
+	      getToken();
+
+	      return node;
+	    }
+
+	    return parseEnd();
+	  }
+
+	  /**
+	   * Evaluated when the expression is not yet ended but expected to end
+	   * @return {Node} res
+	   * @private
+	   */
+	  function parseEnd () {
+	    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
+	   */
+	  /* TODO: implement keeping track on the row number
+	  function row () {
+	    return null;
+	  }
+	  */
+
+	  /**
+	   * 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;
+	  }
+
+	  /**
+	   * Create an error
+	   * @param {String} message
+	   * @return {SyntaxError} instantiated error
+	   * @private
+	   */
+	  function createSyntaxError (message) {
+	    var c = col();
+	    var error = new SyntaxError(message + ' (char ' + c + ')');
+	    error['char'] = c;
+
+	    return error;
+	  }
+
+	  /**
+	   * Create an error
+	   * @param {String} message
+	   * @return {Error} instantiated error
+	   * @private
+	   */
+	  function createError (message) {
+	    var c = col();
+	    var error = new Error(message + ' (char ' + c + ')');
+	    error['char'] = c;
+
+	    return error;
+	  }
+
+	  return parse;
+	};
 
 /***/ },
-/* 17 */
+/* 20 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
-	var _parse = __webpack_require__(16);
-
-	/**
-	 * @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
-	 *
-	 * 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(
-	        'Constructor must be called with the new operator');
-	  }
-
-	  if (!(math instanceof Object)) {
-	    throw new TypeError('Object expected as parameter math');
-	  }
-
-	  this.math = math;
-	  this.scope = {};
-	}
-
-	/**
-	 * Parse an expression and return the parsed function node.
-	 * The node tree can be compiled via `code = node.compile(math)`,
-	 * and the compiled code can be executed as `code.eval([scope])`
-	 * @param {String} expr
-	 * @return {Node} node
-	 * @throws {Error}
-	 */
-	Parser.prototype.parse = function (expr) {
-	  throw new Error('Parser.parse is deprecated. Use math.parse instead.');
-	};
-
-	/**
-	 * Parse and compile an expression, return the compiled javascript code.
-	 * The node can be evaluated via code.eval([scope])
-	 * @param {String} expr
-	 * @return {{eval: function}} code
-	 * @throws {Error}
-	 */
-	Parser.prototype.compile = function (expr) {
-	  throw new Error('Parser.compile is deprecated. Use math.compile instead.');
-	};
-
-	/**
-	 * 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) {
-	  // TODO: validate arguments
-	  return _parse(expr)
-	      .compile(this.math)
-	      .eval(this.scope);
-	};
-
-	/**
-	 * 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) {
-	  // TODO: validate arguments
-	  return this.scope[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) {
-	  // TODO: validate arguments
-	  return this.scope[name] = value;
-	};
-
-	/**
-	 * Remove a variable from the parsers scope
-	 * @param {String} name
-	 */
-	Parser.prototype.remove = function (name) {
-	  // TODO: validate arguments
-	  delete this.scope[name];
-	};
-
-	/**
-	 * Clear the scope with variables and functions
-	 */
-	Parser.prototype.clear = function () {
-	  for (var name in this.scope) {
-	    if (this.scope.hasOwnProperty(name)) {
-	      delete this.scope[name];
-	    }
-	  }
-	};
-
-	module.exports = Parser;
-
+	module.exports = function (math) {
+
+	  var _parse = math.expression.parse;
+
+	  /**
+	   * @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
+	   *
+	   * Example usage:
+	   *    var parser = new Parser();
+	   *    // 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();
+	   *
+	   */
+	  function Parser() {
+	    if (!(this instanceof Parser)) {
+	      throw new SyntaxError(
+	          'Constructor must be called with the new operator');
+	    }
+	    this.scope = {};
+	  }
+
+	  /**
+	   * Parse an expression and return the parsed function node.
+	   * The node tree can be compiled via `code = node.compile(math)`,
+	   * and the compiled code can be executed as `code.eval([scope])`
+	   * @param {String} expr
+	   * @return {Node} node
+	   * @throws {Error}
+	   */
+	  Parser.prototype.parse = function (expr) {
+	    throw new Error('Parser.parse is deprecated. Use math.parse instead.');
+	  };
+
+	  /**
+	   * Parse and compile an expression, return the compiled javascript code.
+	   * The node can be evaluated via code.eval([scope])
+	   * @param {String} expr
+	   * @return {{eval: function}} code
+	   * @throws {Error}
+	   */
+	  Parser.prototype.compile = function (expr) {
+	    throw new Error('Parser.compile is deprecated. Use math.compile instead.');
+	  };
+
+	  /**
+	   * 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) {
+	    // TODO: validate arguments
+	    return _parse(expr)
+	        .compile(math)
+	        .eval(this.scope);
+	  };
+
+	  /**
+	   * 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) {
+	    // TODO: validate arguments
+	    return this.scope[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) {
+	    // TODO: validate arguments
+	    return this.scope[name] = value;
+	  };
+
+	  /**
+	   * Remove a variable from the parsers scope
+	   * @param {String} name
+	   */
+	  Parser.prototype.remove = function (name) {
+	    // TODO: validate arguments
+	    delete this.scope[name];
+	  };
+
+	  /**
+	   * Clear the scope with variables and functions
+	   */
+	  Parser.prototype.clear = function () {
+	    for (var name in this.scope) {
+	      if (this.scope.hasOwnProperty(name)) {
+	        delete this.scope[name];
+	      }
+	    }
+	  };
+
+	  return Parser;
+	};
 
 /***/ },
-/* 18 */
+/* 21 */
 /***/ function(module, exports, __webpack_require__) {
 
 	// constants
-	exports.e = __webpack_require__(185);
-	exports.E = __webpack_require__(185);
-	exports['false'] = __webpack_require__(186);
-	exports.i = __webpack_require__(187);
-	exports['Infinity'] = __webpack_require__(188);
-	exports.LN2 = __webpack_require__(189);
-	exports.LN10 = __webpack_require__(190);
-	exports.LOG2E = __webpack_require__(191);
-	exports.LOG10E = __webpack_require__(192);
-	exports.NaN = __webpack_require__(193);
-	exports['null'] = __webpack_require__(194);
-	exports.pi = __webpack_require__(195);
-	exports.PI = __webpack_require__(195);
-	exports.phi = __webpack_require__(196);
-	exports.SQRT1_2 = __webpack_require__(197);
-	exports.SQRT2 = __webpack_require__(198);
-	exports.tau = __webpack_require__(199);
-	exports['true'] = __webpack_require__(200);
-	exports.version = __webpack_require__(201);
+	exports.e = __webpack_require__(189);
+	exports.E = __webpack_require__(189);
+	exports['false'] = __webpack_require__(190);
+	exports.i = __webpack_require__(191);
+	exports['Infinity'] = __webpack_require__(192);
+	exports.LN2 = __webpack_require__(193);
+	exports.LN10 = __webpack_require__(194);
+	exports.LOG2E = __webpack_require__(195);
+	exports.LOG10E = __webpack_require__(196);
+	exports.NaN = __webpack_require__(197);
+	exports['null'] = __webpack_require__(198);
+	exports.pi = __webpack_require__(199);
+	exports.PI = __webpack_require__(199);
+	exports.phi = __webpack_require__(200);
+	exports.SQRT1_2 = __webpack_require__(201);
+	exports.SQRT2 = __webpack_require__(202);
+	exports.tau = __webpack_require__(203);
+	exports['true'] = __webpack_require__(204);
+	exports.version = __webpack_require__(205);
 
 	// functions - arithmetic
-	exports.abs = __webpack_require__(206);
-	exports.add = __webpack_require__(207);
-	exports.ceil = __webpack_require__(208);
-	exports.cube = __webpack_require__(209);
-	exports.divide = __webpack_require__(210);
-	exports.dotDivide = __webpack_require__(211);
-	exports.dotMultiply = __webpack_require__(212);
-	exports.dotPow = __webpack_require__(213);
-	exports.exp = __webpack_require__(214);
-	exports.fix = __webpack_require__(215);
-	exports.floor = __webpack_require__(216);
-	exports.gcd = __webpack_require__(217);
-	exports.lcm = __webpack_require__(218);
-	exports.log = __webpack_require__(219);
-	exports.log10 = __webpack_require__(220);
-	exports.mod = __webpack_require__(221);
-	exports.multiply = __webpack_require__(222);
-	exports.norm = __webpack_require__(223);
-	exports.nthRoot = __webpack_require__(224);
-	exports.pow = __webpack_require__(225);
-	exports.round = __webpack_require__(226);
-	exports.sign = __webpack_require__(227);
-	exports.sqrt = __webpack_require__(228);
-	exports.square = __webpack_require__(229);
-	exports.subtract = __webpack_require__(230);
-	exports.unaryMinus = __webpack_require__(231);
-	exports.unaryPlus = __webpack_require__(232);
-	exports.xgcd = __webpack_require__(233);
+	exports.abs = __webpack_require__(209);
+	exports.add = __webpack_require__(210);
+	exports.ceil = __webpack_require__(211);
+	exports.cube = __webpack_require__(212);
+	exports.divide = __webpack_require__(213);
+	exports.dotDivide = __webpack_require__(214);
+	exports.dotMultiply = __webpack_require__(215);
+	exports.dotPow = __webpack_require__(216);
+	exports.exp = __webpack_require__(217);
+	exports.fix = __webpack_require__(218);
+	exports.floor = __webpack_require__(219);
+	exports.gcd = __webpack_require__(220);
+	exports.lcm = __webpack_require__(221);
+	exports.log = __webpack_require__(222);
+	exports.log10 = __webpack_require__(223);
+	exports.mod = __webpack_require__(224);
+	exports.multiply = __webpack_require__(225);
+	exports.norm = __webpack_require__(226);
+	exports.nthRoot = __webpack_require__(227);
+	exports.pow = __webpack_require__(228);
+	exports.round = __webpack_require__(229);
+	exports.sign = __webpack_require__(230);
+	exports.sqrt = __webpack_require__(231);
+	exports.square = __webpack_require__(232);
+	exports.subtract = __webpack_require__(233);
+	exports.unaryMinus = __webpack_require__(234);
+	exports.unaryPlus = __webpack_require__(235);
+	exports.xgcd = __webpack_require__(236);
 
 	// functions - bitwise
-	exports.bitAnd = __webpack_require__(234);
-	exports.bitNot = __webpack_require__(235);
-	exports.bitOr = __webpack_require__(236);
-	exports.bitXor = __webpack_require__(237);
-	exports.leftShift = __webpack_require__(238);
-	exports.rightArithShift = __webpack_require__(239);
-	exports.rightLogShift = __webpack_require__(240);
+	exports.bitAnd = __webpack_require__(237);
+	exports.bitNot = __webpack_require__(238);
+	exports.bitOr = __webpack_require__(239);
+	exports.bitXor = __webpack_require__(240);
+	exports.leftShift = __webpack_require__(241);
+	exports.rightArithShift = __webpack_require__(242);
+	exports.rightLogShift = __webpack_require__(243);
 
 	// functions - complex
-	exports.arg = __webpack_require__(241);
-	exports.conj = __webpack_require__(242);
-	exports.re = __webpack_require__(243);
-	exports.im = __webpack_require__(244);
+	exports.arg = __webpack_require__(244);
+	exports.conj = __webpack_require__(245);
+	exports.re = __webpack_require__(246);
+	exports.im = __webpack_require__(247);
 
 	// functions - construction
-	exports.bignumber = __webpack_require__(245);
-	exports['boolean'] = __webpack_require__(246);
-	exports.complex = __webpack_require__(247);
-	exports.index = __webpack_require__(248);
-	exports.matrix = __webpack_require__(249);
-	exports.number = __webpack_require__(250);
-	exports.string = __webpack_require__(251);
-	exports.unit = __webpack_require__(252);
+	exports.bignumber = __webpack_require__(248);
+	exports['boolean'] = __webpack_require__(249);
+	exports.complex = __webpack_require__(250);
+	exports.index = __webpack_require__(251);
+	exports.matrix = __webpack_require__(252);
+	exports.number = __webpack_require__(253);
+	exports.string = __webpack_require__(254);
+	exports.unit = __webpack_require__(255);
 
 	// functions - expression
-	exports['eval'] =  __webpack_require__(253);
-	exports.help =  __webpack_require__(254);
+	exports['eval'] =  __webpack_require__(256);
+	exports.help =  __webpack_require__(257);
 
 	// functions - logical
-	exports['and'] = __webpack_require__(255);
-	exports['not'] = __webpack_require__(256);
-	exports['or'] = __webpack_require__(257);
-	exports['xor'] = __webpack_require__(258);
+	exports['and'] = __webpack_require__(258);
+	exports['not'] = __webpack_require__(259);
+	exports['or'] = __webpack_require__(260);
+	exports['xor'] = __webpack_require__(261);
 
 	// functions - matrix
-	exports['concat'] = __webpack_require__(259);
-	exports.cross = __webpack_require__(260);
-	exports.det = __webpack_require__(261);
-	exports.diag = __webpack_require__(262);
-	exports.dot = __webpack_require__(263);
-	exports.eye = __webpack_require__(264);
-	exports.flatten = __webpack_require__(265);
-	exports.inv = __webpack_require__(266);
-	exports.ones = __webpack_require__(267);
-	exports.range = __webpack_require__(268);
-	exports.resize = __webpack_require__(269);
-	exports.size = __webpack_require__(270);
-	exports.squeeze = __webpack_require__(271);
-	exports.subset = __webpack_require__(272);
-	exports.trace = __webpack_require__(273);
-	exports.transpose = __webpack_require__(274);
-	exports.zeros = __webpack_require__(275);
+	exports['concat'] = __webpack_require__(262);
+	exports.cross = __webpack_require__(263);
+	exports.det = __webpack_require__(264);
+	exports.diag = __webpack_require__(265);
+	exports.dot = __webpack_require__(266);
+	exports.eye = __webpack_require__(267);
+	exports.flatten = __webpack_require__(268);
+	exports.inv = __webpack_require__(269);
+	exports.ones = __webpack_require__(270);
+	exports.range = __webpack_require__(271);
+	exports.resize = __webpack_require__(272);
+	exports.size = __webpack_require__(273);
+	exports.squeeze = __webpack_require__(274);
+	exports.subset = __webpack_require__(275);
+	exports.trace = __webpack_require__(276);
+	exports.transpose = __webpack_require__(277);
+	exports.zeros = __webpack_require__(278);
 
 	// functions - probability
-	exports.combinations = __webpack_require__(276);
+	exports.combinations = __webpack_require__(279);
 	//exports.distribution = require('./function/probability/distribution');
-	exports.factorial = __webpack_require__(277);
-	exports.gamma = __webpack_require__(278);
-	exports.permutations = __webpack_require__(279);
-	exports.pickRandom = __webpack_require__(280);
-	exports.random = __webpack_require__(281);
-	exports.randomInt = __webpack_require__(282);
+	exports.factorial = __webpack_require__(280);
+	exports.gamma = __webpack_require__(281);
+	exports.permutations = __webpack_require__(282);
+	exports.pickRandom = __webpack_require__(283);
+	exports.random = __webpack_require__(284);
+	exports.randomInt = __webpack_require__(285);
 
 	// functions - relational
-	exports.compare = __webpack_require__(283);
-	exports.deepEqual = __webpack_require__(284);
-	exports['equal'] = __webpack_require__(285);
-	exports.larger = __webpack_require__(286);
-	exports.largerEq = __webpack_require__(287);
-	exports.smaller = __webpack_require__(288);
-	exports.smallerEq = __webpack_require__(289);
-	exports.unequal = __webpack_require__(290);
+	exports.compare = __webpack_require__(286);
+	exports.deepEqual = __webpack_require__(287);
+	exports['equal'] = __webpack_require__(288);
+	exports.larger = __webpack_require__(289);
+	exports.largerEq = __webpack_require__(290);
+	exports.smaller = __webpack_require__(291);
+	exports.smallerEq = __webpack_require__(292);
+	exports.unequal = __webpack_require__(293);
 
 	// functions - statistics
-	exports.max = __webpack_require__(291);
-	exports.mean = __webpack_require__(292);
-	exports.median = __webpack_require__(293);
-	exports.min = __webpack_require__(294);
-	exports.prod = __webpack_require__(295);
-	exports.std = __webpack_require__(296);
-	exports.sum = __webpack_require__(297);
-	exports['var'] = __webpack_require__(298);
+	exports.max = __webpack_require__(294);
+	exports.mean = __webpack_require__(295);
+	exports.median = __webpack_require__(296);
+	exports.min = __webpack_require__(297);
+	exports.prod = __webpack_require__(298);
+	exports.std = __webpack_require__(299);
+	exports.sum = __webpack_require__(300);
+	exports['var'] = __webpack_require__(301);
 
 	// functions - trigonometry
-	exports.acos = __webpack_require__(299);
-	exports.acosh = __webpack_require__(300);
-	exports.acot = __webpack_require__(301);
-	exports.acoth = __webpack_require__(302);
-	exports.acsc = __webpack_require__(303);
-	exports.acsch = __webpack_require__(304);
-	exports.asec = __webpack_require__(305);
-	exports.asech = __webpack_require__(306);
-	exports.asin = __webpack_require__(307);
-	exports.asinh = __webpack_require__(308);
-	exports.atan = __webpack_require__(309);
-	exports.atanh = __webpack_require__(310);
-	exports.atan2 = __webpack_require__(311);
-	exports.cos = __webpack_require__(312);
-	exports.cosh = __webpack_require__(313);
-	exports.cot = __webpack_require__(314);
-	exports.coth = __webpack_require__(315);
-	exports.csc = __webpack_require__(316);
-	exports.csch = __webpack_require__(317);
-	exports.sec = __webpack_require__(318);
-	exports.sech = __webpack_require__(319);
-	exports.sin = __webpack_require__(320);
-	exports.sinh = __webpack_require__(321);
-	exports.tan = __webpack_require__(322);
-	exports.tanh = __webpack_require__(323);
+	exports.acos = __webpack_require__(302);
+	exports.acosh = __webpack_require__(303);
+	exports.acot = __webpack_require__(304);
+	exports.acoth = __webpack_require__(305);
+	exports.acsc = __webpack_require__(306);
+	exports.acsch = __webpack_require__(307);
+	exports.asec = __webpack_require__(308);
+	exports.asech = __webpack_require__(309);
+	exports.asin = __webpack_require__(310);
+	exports.asinh = __webpack_require__(311);
+	exports.atan = __webpack_require__(312);
+	exports.atanh = __webpack_require__(313);
+	exports.atan2 = __webpack_require__(314);
+	exports.cos = __webpack_require__(315);
+	exports.cosh = __webpack_require__(316);
+	exports.cot = __webpack_require__(317);
+	exports.coth = __webpack_require__(318);
+	exports.csc = __webpack_require__(319);
+	exports.csch = __webpack_require__(320);
+	exports.sec = __webpack_require__(321);
+	exports.sech = __webpack_require__(322);
+	exports.sin = __webpack_require__(323);
+	exports.sinh = __webpack_require__(324);
+	exports.tan = __webpack_require__(325);
+	exports.tanh = __webpack_require__(326);
 
 	// functions - units
-	exports.to = __webpack_require__(324);
+	exports.to = __webpack_require__(327);
 
 	// functions - utils
-	exports.clone =  __webpack_require__(325);
-	exports.map =  __webpack_require__(326);
-	exports.filter =  __webpack_require__(327);
-	exports.forEach =  __webpack_require__(328);
-	exports.format =  __webpack_require__(329);
+	exports.clone =  __webpack_require__(328);
+	exports.map =  __webpack_require__(329);
+	exports.filter =  __webpack_require__(330);
+	exports.forEach =  __webpack_require__(331);
+	exports.format =  __webpack_require__(332);
 	// exports.print =  require('./function/utils/print'); // TODO: add documentation for print as soon as the parser supports objects.
-	exports['import'] =  __webpack_require__(330);
-	exports.sort =  __webpack_require__(331);
-	exports['typeof'] =  __webpack_require__(332);
+	exports['import'] =  __webpack_require__(333);
+	exports.sort =  __webpack_require__(334);
+	exports['typeof'] =  __webpack_require__(335);
 
 
 /***/ },
-/* 19 */
+/* 22 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
-	var BigNumber = __webpack_require__(5);
-	var Complex   = __webpack_require__(7);
-	var Help      = __webpack_require__(12);
-	var Index     = __webpack_require__(9);
-	var Matrix    = __webpack_require__(10);
-	var Range     = __webpack_require__(8);
-	var ResultSet = __webpack_require__(13);
-	var Unit      = __webpack_require__(11);
-
-	/**
-	 * Instantiate mathjs data types from their JSON representation
-	 * @param {string} key
-	 * @param {*} value
-	 * @returns {*} Returns the revived object
-	 */
-	function reviver(key, value) {
-	  var type = value && value.mathjs;
-
-	  switch (type) {
-	    case 'BigNumber': return BigNumber.fromJSON(value);
-	    case 'Complex':   return Complex.fromJSON(value);
-	    case 'Help':      return Help.fromJSON(value);
-	    case 'Index':     return Index.fromJSON(value);
-	    case 'Matrix':    return Matrix.fromJSON(value);
-	    case 'Range':     return Range.fromJSON(value);
-	    case 'ResultSet': return ResultSet.fromJSON(value);
-	    case 'Unit':      return Unit.fromJSON(value);
+	module.exports = function (math) {
+	  /**
+	   * Instantiate mathjs data types from their JSON representation
+	   * @param {string} key
+	   * @param {*} value
+	   * @returns {*} Returns the revived object
+	   */
+	  function reviver(key, value) {
+	    var name = value && value.mathjs;
+
+	    var constructor = math.type[name];
+	    if (constructor && constructor.fromJSON) {
+	      return constructor.fromJSON(value);
+	    }
+
+	    return value;
 	  }
 
-	  return value;
-	}
-
-	module.exports = reviver;
-
+	  return reviver;
+	};
 
 /***/ },
-/* 20 */
+/* 23 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	var BigNumber = __webpack_require__(5);
-	var errorTransform = __webpack_require__(203).transform;
+	var errorTransform = __webpack_require__(207).transform;
 	var isNumber = __webpack_require__(3).isNumber;
-	var argsToArray = __webpack_require__(165).argsToArray;
+	var argsToArray = __webpack_require__(168).argsToArray;
 
 	/**
 	 * Attach a transform function to math.range
@@ -5879,15 +9180,15 @@
 
 
 /***/ },
-/* 21 */
+/* 24 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
-	var SymbolNode = __webpack_require__(183);
-	var isBoolean = __webpack_require__(204).isBoolean;
-	var argsToArray = __webpack_require__(165).argsToArray;
-	var ArgumentsError = __webpack_require__(167);
+	var SymbolNode = __webpack_require__(187);
+	var isBoolean = __webpack_require__(208).isBoolean;
+	var argsToArray = __webpack_require__(168).argsToArray;
+	var ArgumentsError = __webpack_require__(170);
 
 	/**
 	 * Attach a transform function to math.filter
@@ -5949,13 +9250,11 @@
 
 
 /***/ },
-/* 22 */
+/* 25 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
-	var Matrix = __webpack_require__(10);
-
 	/**
 	 * Attach a transform function to math.forEach
 	 * Adds a property transform containing the transform function.
@@ -5964,6 +9263,9 @@
 	 * @param {Object} math
 	 */
 	module.exports = function (math) {
+
+	  var Matrix = math.type.Matrix;
+
 	  var transform = function (x, callback) {
 	    if (arguments.length != 2) {
 	      throw new math.error.ArgumentsError('forEach', arguments.length, 2);
@@ -6000,7 +9302,7 @@
 
 
 /***/ },
-/* 23 */
+/* 26 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
@@ -6008,9 +9310,7 @@
 	var BigNumber = __webpack_require__(5);
 	var Range = __webpack_require__(8);
 	var Index = __webpack_require__(9);
-	var Matrix = __webpack_require__(10);
 	var isNumber = __webpack_require__(3).isNumber;
-	var isArray = Array.isArray;
 
 	/**
 	 * Attach a transform function to math.index
@@ -6055,18 +9355,11 @@
 
 
 /***/ },
-/* 24 */
+/* 27 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
-	var Matrix = __webpack_require__(10);
-	var BigNumber = __webpack_require__(5);
-	var Range = __webpack_require__(8);
-	var Index = __webpack_require__(9);
-	var isNumber = __webpack_require__(3).isNumber;
-	var isArray = Array.isArray;
-
 	/**
 	 * Attach a transform function to math.map
 	 * Adds a property transform containing the transform function.
@@ -6075,6 +9368,9 @@
 	 * @param {Object} math
 	 */
 	module.exports = function (math) {
+
+	  var Matrix = math.type.Matrix;
+
 	  var transform = function (x, callback) {
 	    if (arguments.length != 2) {
 	      throw new math.error.ArgumentsError('map', arguments.length, 2);
@@ -6083,7 +9379,7 @@
 	    if (Array.isArray(x)) {
 	      return _mapArray(x, callback, x);
 	    } else if (x instanceof Matrix) {
-	      return new Matrix(_mapArray(x.valueOf(), callback, x))
+	      return math.matrix(_mapArray(x.valueOf(), callback, x));
 	    } else {
 	      throw new math.error.UnsupportedTypeError('map', math['typeof'](x));
 	    }
@@ -6112,16 +9408,15 @@
 
 
 /***/ },
-/* 25 */
+/* 28 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	var BigNumber = __webpack_require__(5);
-	var errorTransform = __webpack_require__(203).transform;
+	var errorTransform = __webpack_require__(207).transform;
 	var isNumber = __webpack_require__(3).isNumber;
-	var isCollection = __webpack_require__(14).isCollection;
-	var argsToArray = __webpack_require__(165).argsToArray;
+	var argsToArray = __webpack_require__(168).argsToArray;
 
 	/**
 	 * Attach a transform function to math.max
@@ -6132,6 +9427,9 @@
 	 * @param {Object} math
 	 */
 	module.exports = function (math) {
+
+	  var isCollection = math.collection.isCollection;
+
 	  var transform = function () {
 	    var args = argsToArray(arguments);
 
@@ -6161,16 +9459,15 @@
 
 
 /***/ },
-/* 26 */
+/* 29 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	var BigNumber = __webpack_require__(5);
-	var errorTransform = __webpack_require__(203).transform;
+	var errorTransform = __webpack_require__(207).transform;
 	var isNumber = __webpack_require__(3).isNumber;
-	var isCollection = __webpack_require__(14).isCollection;
-	var argsToArray = __webpack_require__(165).argsToArray;
+	var argsToArray = __webpack_require__(168).argsToArray;
 
 	/**
 	 * Attach a transform function to math.mean
@@ -6181,6 +9478,9 @@
 	 * @param {Object} math
 	 */
 	module.exports = function (math) {
+
+	  var isCollection = math.collection.isCollection;
+
 	  var transform = function () {
 	    var args = argsToArray(arguments);
 
@@ -6210,16 +9510,15 @@
 
 
 /***/ },
-/* 27 */
+/* 30 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	var BigNumber = __webpack_require__(5);
-	var errorTransform = __webpack_require__(203).transform;
+	var errorTransform = __webpack_require__(207).transform;
 	var isNumber = __webpack_require__(3).isNumber;
-	var isCollection = __webpack_require__(14).isCollection;
-	var argsToArray = __webpack_require__(165).argsToArray;
+	var argsToArray = __webpack_require__(168).argsToArray;
 
 	/**
 	 * Attach a transform function to math.min
@@ -6230,6 +9529,9 @@
 	 * @param {Object} math
 	 */
 	module.exports = function (math) {
+
+	  var isCollection = math.collection.isCollection;
+
 	  var transform = function () {
 	    var args = argsToArray(arguments);
 
@@ -6259,13 +9561,13 @@
 
 
 /***/ },
-/* 28 */
+/* 31 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
-	var isBoolean = __webpack_require__(204).isBoolean;
-	var argsToArray = __webpack_require__(165).argsToArray;
+	var isBoolean = __webpack_require__(208).isBoolean;
+	var argsToArray = __webpack_require__(168).argsToArray;
 
 	/**
 	 * Attach a transform function to math.range
@@ -6294,14 +9596,14 @@
 
 
 /***/ },
-/* 29 */
+/* 32 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
-	var errorTransform = __webpack_require__(203).transform;
-	var isBoolean = __webpack_require__(204).isBoolean;
-	var argsToArray = __webpack_require__(165).argsToArray;
+	var errorTransform = __webpack_require__(207).transform;
+	var isBoolean = __webpack_require__(208).isBoolean;
+	var argsToArray = __webpack_require__(168).argsToArray;
 
 	/**
 	 * Attach a transform function to math.subset
@@ -6327,13 +9629,13 @@
 
 
 /***/ },
-/* 30 */
+/* 33 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var string = __webpack_require__(205);
+	  var string = __webpack_require__(175);
 
 	  /**
 	   * @constructor Chain
@@ -6428,16 +9730,846 @@
 
 
 /***/ },
-/* 31 */
+/* 34 */
+/***/ function(module, exports, __webpack_require__) {
+
+	'use strict';
+
+	module.exports = function (math) {
+	  var util = __webpack_require__(174),
+
+	      // take the BigNumber instance the provided math.js instance
+	      BigNumber = math.type.BigNumber,
+	      collection = math.collection,
+
+	      isCollection = collection.isCollection,
+	      isNumber = util.number.isNumber,
+	      isString = util.string.isString,
+	      isBoolean = util['boolean'].isBoolean;
+
+	  /**
+	   * Create a BigNumber, which can store numbers with arbitrary precision.
+	   * When a matrix is provided, all elements will be converted to BigNumber.
+	   *
+	   * Syntax:
+	   *
+	   *    math.bignumber(x)
+	   *
+	   * Examples:
+	   *
+	   *    0.1 + 0.2;                                  // returns Number 0.30000000000000004
+	   *    math.bignumber(0.1) + math.bignumber(0.2);  // returns BigNumber 0.3
+	   *
+	   *
+	   *    7.2e500;                                    // returns Number Infinity
+	   *    math.bignumber('7.2e500');                  // returns BigNumber 7.2e500
+	   *
+	   * See also:
+	   *
+	   *    boolean, complex, index, matrix, string, unit
+	   *
+	   * @param {Number | String | Array | Matrix | Boolean | null} [value]  Value for the big number,
+	   *                                                    0 by default.
+	   * @returns {BigNumber} The created bignumber
+	   */
+	  math.bignumber = function bignumber(value) {
+	    if (arguments.length > 1) {
+	      throw new math.error.ArgumentsError('bignumber', arguments.length, 0, 1);
+	    }
+
+	    if ((value instanceof BigNumber) || isNumber(value) || isString(value)) {
+	      return new BigNumber(value);
+	    }
+
+	    if (isBoolean(value) || value === null) {
+	      return new BigNumber(+value);
+	    }
+
+	    if (isCollection(value)) {
+	      return collection.deepMap(value, bignumber);
+	    }
+
+	    if (arguments.length == 0) {
+	      return new BigNumber(0);
+	    }
+
+	    throw new math.error.UnsupportedTypeError('bignumber', math['typeof'](value));
+	  };
+	};
+
+
+/***/ },
+/* 35 */
+/***/ function(module, exports, __webpack_require__) {
+
+	'use strict';
+
+	module.exports = function (math) {
+	  var util = __webpack_require__(174),
+
+	      BigNumber = math.type.BigNumber,
+	      collection = math.collection,
+
+	      isCollection = collection.isCollection,
+	      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.
+	   * When value is a matrix, all elements will be converted to boolean.
+	   *
+	   * Syntax:
+	   *
+	   *    math.boolean(x)
+	   *
+	   * Examples:
+	   *
+	   *    math.boolean(0);     // returns false
+	   *    math.boolean(1);     // returns true
+	   *    math.boolean(-3);     // returns true
+	   *    math.boolean('true');     // returns true
+	   *    math.boolean('false');     // returns false
+	   *    math.boolean([1, 0, 1, 1]);     // returns [true, false, true, true]
+	   *
+	   * See also:
+	   *
+	   *    bignumber, complex, index, matrix, string, unit
+	   *
+	   * @param {String | Number | Boolean | Array | Matrix | null} value  A value of any type
+	   * @return {Boolean | Array | Matrix} The boolean value
+	   */
+	  math['boolean'] = function bool (value) {
+	    if (arguments.length != 1) {
+	      throw new math.error.ArgumentsError('boolean', arguments.length, 0, 1);
+	    }
+
+	    if (value === 'true' || value === true) {
+	      return true;
+	    }
+
+	    if (value === 'false' || value === false || value === null) {
+	      return false;
+	    }
+
+	    if (value instanceof Boolean) {
+	      return value == true;
+	    }
+
+	    if (isNumber(value)) {
+	      return (value !== 0);
+	    }
+
+	    if (value instanceof BigNumber) {
+	      return !value.isZero();
+	    }
+
+	    if (isString(value)) {
+	      // try case insensitive
+	      var lcase = value.toLowerCase();
+	      if (lcase === 'true') {
+	        return true;
+	      }
+	      else if (lcase === 'false') {
+	        return false;
+	      }
+
+	      // test whether value is a valid number
+	      var num = Number(value);
+	      if (value != '' && !isNaN(num)) {
+	        return (num !== 0);
+	      }
+	    }
+
+	    if (isCollection(value)) {
+	      return collection.deepMap(value, bool);
+	    }
+
+	    throw new SyntaxError(value.toString() + ' is no valid boolean');
+	  };
+	};
+
+
+/***/ },
+/* 36 */
+/***/ function(module, exports, __webpack_require__) {
+
+	'use strict';
+
+	module.exports = function (math) {
+	  var util = __webpack_require__(174),
+
+	      BigNumber = math.type.BigNumber,
+	      Complex = __webpack_require__(7),
+	      collection = math.collection,
+
+	      isCollection = collection.isCollection,
+	      isNumber = util.number.isNumber,
+	      isString = util.string.isString,
+	      isComplex = Complex.isComplex;
+
+	  /**
+	   * Create a complex value or convert a value to a complex value.
+	   *
+	   * Syntax:
+	   *
+	   *     math.complex()                           // creates a complex value with zero
+	   *                                              // as real and imaginary part.
+	   *     math.complex(re : number, im : string)   // creates a complex value with provided
+	   *                                              // values for real and imaginary part.
+	   *     math.complex(re : number)                // creates a complex value with provided
+	   *                                              // real value and zero imaginary part.
+	   *     math.complex(complex : Complex)          // clones the provided complex value.
+	   *     math.complex(arg : string)               // parses a string into a complex value.
+	   *     math.complex(array : Array)              // converts the elements of the array
+	   *                                              // or matrix element wise into a
+	   *                                              // complex value.
+	   *     math.complex({re: number, im: number})   // creates a complex value with provided
+	   *                                              // values for real an imaginary part.
+	   *     math.complex({r: number, phi: number})   // creates a complex value with provided
+	   *                                              // polar coordinates
+	   *
+	   * Examples:
+	   *
+	   *    var a = math.complex(3, -4);     // a = Complex 3 - 4i
+	   *    a.re = 5;                        // a = Complex 5 - 4i
+	   *    var i = a.im;                    // Number -4;
+	   *    var b = math.complex('2 + 6i');  // Complex 2 + 6i
+	   *    var c = math.complex();          // Complex 0 + 0i
+	   *    var d = math.add(a, b);          // Complex 5 + 2i
+	   *
+	   * See also:
+	   *
+	   *    bignumber, boolean, index, matrix, number, string, unit
+	   *
+	   * @param {* | Array | Matrix} [args]
+	   *            Arguments specifying the real and imaginary part of the complex number
+	   * @return {Complex | Array | Matrix} Returns a complex value
+	   */
+	  math.complex = function complex(args) {
+	    switch (arguments.length) {
+	      case 0:
+	        // no parameters. Set re and im zero
+	        return new Complex(0, 0);
+
+	      case 1:
+	        // parse string into a complex number
+	        var arg = arguments[0];
+
+	        if (isNumber(arg)) {
+	          return new Complex(arg, 0);
+	        }
+
+	        if (arg instanceof BigNumber) {
+	          // convert to Number
+	          return new Complex(arg.toNumber(), 0);
+	        }
+
+	        if (isComplex(arg)) {
+	          // create a clone
+	          return arg.clone();
+	        }
+
+	        if (isString(arg)) {
+	          var c = Complex.parse(arg);
+	          if (c) {
+	            return c;
+	          }
+	          else {
+	            throw new SyntaxError('String "' + arg + '" is no valid complex number');
+	          }
+	        }
+
+	        if (isCollection(arg)) {
+	          return collection.deepMap(arg, complex);
+	        }
+
+	        if (typeof arg === 'object') {
+	          if('re' in arg && 'im' in arg) {
+	            return new Complex(arg.re, arg.im);
+	          } else if ('r' in arg && 'phi' in arg) {
+	            return Complex.fromPolar(arg.r, arg.phi);
+	          }
+	        } 
+
+	        throw new TypeError('Two numbers, single string or an fitting object expected in function complex');
+
+	      case 2:
+	        // re and im provided
+	        var re = arguments[0],
+	            im = arguments[1];
+
+	        // convert re to number
+	        if (re instanceof BigNumber) {
+	          re = re.toNumber();
+	        }
+
+	        // convert im to number
+	        if (im instanceof BigNumber) {
+	          im = im.toNumber();
+	        }
+
+	        if (isNumber(re) && isNumber(im)) {
+	          return new Complex(re, im);
+	        }
+	        else {
+	          throw new TypeError('Two numbers or a single string expected in function complex');
+	        }
+
+	      default:
+	        throw new math.error.ArgumentsError('complex', arguments.length, 0, 2);
+	    }
+	  };
+	};
+
+
+/***/ },
+/* 37 */
+/***/ function(module, exports, __webpack_require__) {
+
+	'use strict';
+
+	module.exports = function (math) {
+	  var util = __webpack_require__(174),
+
+	      BigNumber = math.type.BigNumber,
+	      Index = __webpack_require__(9);
+
+	  /**
+	   * Create an index. An Index can store ranges having start, step, and end
+	   * for multiple dimensions.
+	   * Matrix.get, Matrix.set, and math.subset accept an Index as input.
+	   *
+	   * Syntax:
+	   *
+	   *     math.index(range1, range2, ...)
+	   *
+	   * Where:
+	   *
+	   * Each range can be any of:
+	   *
+	   * - An array [start, end]
+	   * - An array [start, end, step]
+	   * - A number
+	   * - An instance of `Range`
+	   *
+	   * The parameters start, end, and step must be integer numbers. Start and end
+	   * are zero based. The start of a range is included, the end is excluded.
+	   *
+	   * Examples:
+	   *
+	   *    var math = math.js
+	   *
+	   *    var b = [1, 2, 3, 4, 5];
+	   *    math.subset(b, math.index([1, 3]));     // returns [2, 3]
+	   *
+	   *    var a = math.matrix([[1, 2], [3, 4]]);
+	   *    a.subset(math.index(0, 1));             // returns 2
+	   *    a.subset(math.index(1, null));          // returns [3, 4]
+	   *
+	   * See also:
+	   *
+	   *    bignumber, boolean, complex, matrix, number, string, unit
+	   *
+	   * @param {...*} ranges   Zero or more ranges or numbers.
+	   * @return {Index}        Returns the created index
+	   */
+	  math.index = function(ranges) {
+	    // downgrade BigNumber to Number
+	    var args = Array.prototype.slice.apply(arguments).map(function (arg) {
+	      if (arg instanceof BigNumber) {
+	        return arg.toNumber();
+	      }
+	      else if (Array.isArray(arg)) {
+	        return arg.map(function (elem) {
+	          return (elem instanceof BigNumber) ? elem.toNumber() : elem;
+	        });
+	      }
+	      else {
+	        return arg;
+	      }
+	    });
+
+	    var res = new Index();
+	    Index.apply(res, args);
+	    return res;
+	  };
+	};
+
+
+/***/ },
+/* 38 */
+/***/ function(module, exports, __webpack_require__) {
+
+	'use strict';
+
+	var string = __webpack_require__(175);
+
+	var isArray = Array.isArray;
+	var isString = string.isString;
+
+	module.exports = function (math) {
+	  var Matrix = math.type.Matrix;
+
+	  /**
+	   * Create a Matrix. The function creates a new `math.type.Matrix` object from
+	   * an `Array`. A Matrix has utility functions to manipulate the data in the
+	   * matrix, like getting the size and getting or setting values in the matrix.
+	   *
+	   * Syntax:
+	   *
+	   *    math.matrix()               // creates an empty matrix using default storage format (dense).
+	   *    math.matrix(data)           // creates a matrix with initial data using default storage format (dense).
+	   *    math.matrix('dense')        // creates an empty matrix using the given storage format.
+	   *    math.matrix(data, 'dense')  // creates a matrix with initial data using the given storage format.
+	   *
+	   * Examples:
+	   *
+	   *    var m = math.matrix([[1, 2], [3, 4]]);
+	   *    m.size();                        // Array [2, 2]
+	   *    m.resize([3, 2], 5);
+	   *    m.valueOf();                     // Array [[1, 2], [3, 4], [5, 5]]
+	   *    m.get([1, 0])                    // number 3
+	   *
+	   * See also:
+	   *
+	   *    bignumber, boolean, complex, index, number, string, unit
+	   *
+	   * @param {Array | Matrix} [data]    A multi dimensional array
+	   * @param {string} [format]          The Matrix storage format
+	   *
+	   * @return {Matrix} The created matrix
+	   */
+	  math.matrix = function matrix(data, format) {
+	    // check arguments
+	    switch (arguments.length) {
+	      case 0:
+	        // set data and format
+	        data = [];
+	        format = 'default';
+	        break;
+	      case 1:
+	        // check data was provided
+	        if (isArray(data)) {
+	          // use default format
+	          format = 'default';          
+	        }
+	        else if (data instanceof Matrix) {
+	          // same format as matrix
+	          format = data.storage();
+	        }
+	        else if (isString(data)) {
+	          // set format
+	          format = data;
+	          // empty array
+	          data = [];
+	        }
+	        break;
+	      case 2:
+	        // check data is an array
+	        if (!isArray(data) && !(data instanceof Matrix)) {
+	          // throw
+	          throw new TypeError('data must be an array value or Matrix instance');
+	        }
+	        break;
+	      default:
+	        throw new math.error.ArgumentsError('matrix', arguments.length, 0, 2);  
+	    }
+
+	    // get storage format constructor
+	    var constructor = Matrix.storage(format);
+
+	    // create instance
+	    return new constructor(data);
+	  };
+	};
+
+
+/***/ },
+/* 39 */
+/***/ function(module, exports, __webpack_require__) {
+
+	'use strict';
+
+	module.exports = function (math) {
+	  var util = __webpack_require__(174);
+
+	  var BigNumber = math.type.BigNumber;
+	  var Unit = math.type.Unit;
+	  var collection = math.collection;
+
+	  var isCollection = collection.isCollection;
+	  var isNumber = util.number.isNumber;
+	  var isBoolean = util['boolean'].isBoolean;
+	  var isString = util.string.isString;
+
+	  /**
+	   * Create a number or convert a string, boolean, or unit to a number.
+	   * When value is a matrix, all elements will be converted to number.
+	   *
+	   * Syntax:
+	   *
+	   *    math.number(value)
+	   *    math.number(unit, valuelessUnit)
+	   *
+	   * Examples:
+	   *
+	   *    math.number(2);                         // returns number 2
+	   *    math.number('7.2');                     // returns number 7.2
+	   *    math.number(true);                      // returns number 1
+	   *    math.number([true, false, true, true]); // returns [1, 0, 1, 1]
+	   *    math.number(math.unit('52cm'), 'm');    // returns 0.52
+	   *
+	   * See also:
+	   *
+	   *    bignumber, boolean, complex, index, matrix, string, unit
+	   *
+	   * @param {String | Number | Boolean | Array | Matrix | Unit | null} [value]  Value to be converted
+	   * @param {Unit | string} [valuelessUnit] A valueless unit, used to convert a unit to a number
+	   * @return {Number | Array | Matrix} The created number
+	   */
+	  math.number = function number (value, valuelessUnit) {
+	    switch (arguments.length) {
+	      case 0:
+	        return 0;
+
+	      case 1:
+	        if (isCollection(value)) {
+	          return collection.deepMap(value, number);
+	        }
+
+	        if (value instanceof BigNumber) {
+	          return value.toNumber();
+	        }
+
+	        if (isString(value)) {
+	          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;
+	        }
+
+	        if (isBoolean(value) || value === null) {
+	          return +value;
+	        }
+
+	        if (isNumber(value)) {
+	          return value;
+	        }
+
+	        if (value instanceof Unit) {
+	          throw new Error('Second argument with valueless unit expected');
+	        }
+
+	        throw new math.error.UnsupportedTypeError('number', math['typeof'](value));
+
+	      case 2:
+	        if (value instanceof Unit && isString(valuelessUnit) || valuelessUnit instanceof Unit) {
+	          return value.toNumber(valuelessUnit);
+	        }
+
+	        throw new math.error.UnsupportedTypeError('number', math['typeof'](value), math['typeof'](valuelessUnit));
+
+
+	      default:
+	        throw new math.error.ArgumentsError('number', arguments.length, 0, 1);
+	    }
+	  };
+	};
+
+
+/***/ },
+/* 40 */
+/***/ function(module, exports, __webpack_require__) {
+
+	'use strict';
+
+	module.exports = function (math) {
+	  var Parser = math.expression.Parser;
+
+	  /**
+	   * Create a parser. The function creates a new `math.expression.Parser` object.
+	   *
+	   * Syntax:
+	   *
+	   *    math.parser()
+	   *
+	   * Examples:
+	   *
+	   *     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();
+	   *
+	   * See also:
+	   *
+	   *    eval, compile, parse
+	   *
+	   * @return {Parser} Parser
+	   */
+	  math.parser = function parser() {
+	    return new Parser();
+	  };
+	};
+
+
+/***/ },
+/* 41 */
+/***/ function(module, exports, __webpack_require__) {
+
+	'use strict';
+
+	module.exports = function (math) {
+	  /**
+	   * Wrap any value in a chain, allowing to perform chained operations on
+	   * the value.
+	   *
+	   * All methods available in the math.js library can be called upon the chain,
+	   * and then will be evaluated with the value itself as first argument.
+	   * The chain can be closed by executing `chain.done()`, which returns
+	   * the final value.
+	   *
+	   * The chain has a number of special functions:
+	   *
+	   * - `done()`     Finalize the chain and return the chain's value.
+	   * - `valueOf()`  The same as `done()`
+	   * - `toString()` Executes `math.format()` onto the chain's value, returning
+	   *                a string representation of the value.
+	   *
+	   * Syntax:
+	   *
+	   *    math.chain(value)
+	   *
+	   * Examples:
+	   *
+	   *     math.chain(3)
+	   *         .add(4)
+	   *         .subtract(2)
+	   *         .done();     // 5
+	   *
+	   *     math.chain( [[1, 2], [3, 4]] )
+	   *         .subset(math.index(0, 0), 8)
+	   *         .multiply(3)
+	   *         .done();     // [[24, 6], [9, 12]]
+	   *
+	   * @param {*} [value]   A value of any type on which to start a chained operation.
+	   * @return {math.chaining.Chain} The created chain
+	   */
+	  math.chain = function(value) {
+	    // TODO: check number of arguments
+	    return new math.chaining.Chain(value);
+	  };
+
+	  // TODO: deprecate math.select in v2.0
+	  math.select = function(value) {
+	    // give a warning once.
+	    if (console && typeof console.log === 'function') {
+	      console.log('WARNING: Function "select" is renamed to "chain". It will be deprecated in v2.0.')
+	    }
+
+	    // replace warning function with chain function
+	    math.select = math.chain;
+	    math.chaining.Chain.prototype['select'] = math.select;
+
+	    return math.chain(value);
+	  }
+	};
+
+
+/***/ },
+/* 42 */
+/***/ function(module, exports, __webpack_require__) {
+
+	'use strict';
+
+	module.exports = function (math) {
+	  var util = __webpack_require__(174),
+
+	      collection = math.collection,
+
+	      number = util.number,
+	      isNumber = util.number.isNumber,
+	      isCollection = collection.isCollection;
+
+	  /**
+	   * Create a string or convert any object into a string.
+	   * Elements of Arrays and Matrices are processed element wise.
+	   *
+	   * Syntax:
+	   *
+	   *    math.string(value)
+	   *
+	   * Examples:
+	   *
+	   *    math.string(4.2);               // returns string '4.2'
+	   *    math.string(math.complex(3, 2); // returns string '3 + 2i'
+	   *
+	   *    var u = math.unit(5, 'km');
+	   *    math.string(u.to('m'));         // returns string '5000 m'
+	   *
+	   *    math.string([true, false]);     // returns ['true', 'false']
+	   *
+	   * See also:
+	   *
+	   *    bignumber, boolean, complex, index, matrix, number, unit
+	   *
+	   * @param {* | Array | Matrix | null} [value]  A value to convert to a string
+	   * @return {String | Array | Matrix} The created string
+	   */
+	  math.string = function string (value) {
+	    switch (arguments.length) {
+	      case 0:
+	        return '';
+
+	      case 1:
+	        if (isNumber(value)) {
+	          return number.format(value);
+	        }
+
+	        if (isCollection(value)) {
+	          return collection.deepMap(value, string);
+	        }
+
+	        if (value === null) {
+	          return 'null';
+	        }
+
+	        return value.toString();
+
+	      default:
+	        throw new math.error.ArgumentsError('string', arguments.length, 0, 1);
+	    }
+	  };
+	};
+
+
+/***/ },
+/* 43 */
+/***/ function(module, exports, __webpack_require__) {
+
+	'use strict';
+
+	module.exports = function (math) {
+	  var util = __webpack_require__(174),
+
+	      BigNumber = math.type.BigNumber,
+	      Unit = __webpack_require__(11),
+	      collection = math.collection,
+
+	      isCollection = collection.isCollection,
+	      isString = util.string.isString;
+
+	  /**
+	   * Create a unit. Depending on the passed arguments, the function
+	   * will create and return a new math.type.Unit object.
+	   * When a matrix is provided, all elements will be converted to units.
+	   *
+	   * Syntax:
+	   *
+	   *     math.unit(unit : string)
+	   *     math.unit(value : number, unit : string)
+	   *
+	   * Examples:
+	   *
+	   *    var a = math.unit(5, 'cm');    // returns Unit 50 mm
+	   *    var b = math.unit('23 kg');    // returns Unit 23 kg
+	   *    a.to('m');                     // returns Unit 0.05 m
+	   *
+	   * See also:
+	   *
+	   *    bignumber, boolean, complex, index, matrix, number, string
+	   *
+	   * @param {* | Array | Matrix} args   A number and unit.
+	   * @return {Unit | Array | Matrix}    The created unit
+	   */
+	  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();
+	        }
+
+	        if (isString(arg)) {
+	          if (Unit.isValuelessUnit(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');
+	        }
+
+	        if (isCollection(args)) {
+	          return collection.deepMap(args, unit);
+	        }
+
+	        throw new TypeError('A string or a number and string expected in function unit');
+
+	      case 2:
+	        // a number and a unit
+
+	        if (arguments[0] instanceof BigNumber) {
+	          // convert value to number
+	          return new Unit(arguments[0].toNumber(), arguments[1]);
+	        }
+	        else {
+	          return new Unit(arguments[0], arguments[1]);
+	        }
+
+	      default:
+	        throw new math.error.ArgumentsError('unit', arguments.length, 1, 2);
+	    }
+	  };
+	};
+
+
+/***/ },
+/* 44 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math, config) {
-	  var util = __webpack_require__(171),
-	      _parse = __webpack_require__(16),
+	  var util = __webpack_require__(174),
+	      _parse = math.expression.parse,
 
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isString = util.string.isString,
 	      isCollection = collection.isCollection;
@@ -6500,16 +10632,16 @@
 
 
 /***/ },
-/* 32 */
+/* 45 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
-	      _parse = __webpack_require__(16),
+	  var util = __webpack_require__(174),
+	      _parse = math.expression.parse,
 
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isString = util.string.isString,
 	      isCollection = collection.isCollection;
@@ -6573,7 +10705,7 @@
 
 
 /***/ },
-/* 33 */
+/* 46 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
@@ -6646,13 +10778,13 @@
 
 
 /***/ },
-/* 34 */
+/* 47 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math, config) {
-	  var _parse = __webpack_require__(16);
+	  var _parse = math.expression.parse;
 
 	  /**
 	   * Parse an expression. Returns a node tree, which can be evaluated by
@@ -6694,21 +10826,20 @@
 
 
 /***/ },
-/* 35 */
+/* 48 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
-	      Matrix = __webpack_require__(10),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
-	      isBoolean = util['boolean'].isBoolean,
+	      isBoolean = util.boolean.isBoolean,
 	      isComplex = Complex.isComplex,
 	      isCollection = collection.isCollection;
 
@@ -6750,11 +10881,11 @@
 	      var re = Math.abs(x.re);
 	      var im = Math.abs(x.im);
 	      if (re >= im) {
-	        var x = im / re;
-	        return re * Math.sqrt(1 + x * x);
+	        var i = im / re;
+	        return re * Math.sqrt(1 + i * i);
 	      }
-	      var y = re / im;
-	      return im * Math.sqrt(1 + y * y);
+	      var j = re / im;
+	      return im * Math.sqrt(1 + j * j);
 	    }
 
 	    if (x instanceof BigNumber) {
@@ -6762,7 +10893,8 @@
 	    }
 
 	    if (isCollection(x)) {
-	      return collection.deepMap(x, abs);
+	      // deep map collection, skip zeros since abs(0) = 0
+	      return collection.deepMap(x, abs, true);
 	    }
 
 	    if (isBoolean(x) || x === null) {
@@ -6775,19 +10907,18 @@
 
 
 /***/ },
-/* 36 */
+/* 49 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
-	      Matrix = __webpack_require__(10),
 	      Unit = __webpack_require__(11),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isBoolean = util['boolean'].isBoolean,
 	      isNumber = util.number.isNumber,
@@ -6841,7 +10972,7 @@
 	        return new Complex(
 	            x + y.re,
 	            y.im
-	        )
+	        );
 	      }
 	    }
 
@@ -6858,7 +10989,7 @@
 	        return new Complex(
 	            x.re + y,
 	            x.im
-	        )
+	        );
 	      }
 	    }
 
@@ -6909,7 +11040,7 @@
 	      }
 
 	      if (x instanceof BigNumber) {
-	        return x.plus(y)
+	        return x.plus(y);
 	      }
 
 	      // downgrade to Number
@@ -6937,17 +11068,17 @@
 
 
 /***/ },
-/* 37 */
+/* 50 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -7003,7 +11134,8 @@
 	    }
 
 	    if (isCollection(x)) {
-	      return collection.deepMap(x, ceil);
+	      // deep map collection, skip zeros since ceil(0) = 0
+	      return collection.deepMap(x, ceil, true);
 	    }
 
 	    if (isBoolean(x) || x === null) {
@@ -7016,17 +11148,17 @@
 
 
 /***/ },
-/* 38 */
+/* 51 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -7088,17 +11220,17 @@
 
 
 /***/ },
-/* 39 */
+/* 52 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function(math) {
-	  var util = __webpack_require__(171);
+	  var util = __webpack_require__(174);
 
 	  var BigNumber = math.type.BigNumber;
 	  var Complex = __webpack_require__(7);
-	  var Matrix = __webpack_require__(10);
+	  var Matrix = math.type.Matrix;
 	  var Unit = __webpack_require__(11);
 
 	  var isNumber = util.number.isNumber;
@@ -7221,13 +11353,13 @@
 
 
 /***/ },
-/* 40 */
+/* 53 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function(math) {
-	  var collection = __webpack_require__(14);
+	  var collection = math.collection;
 	  var isCollection = collection.isCollection;
 
 	  /**
@@ -7292,13 +11424,13 @@
 
 
 /***/ },
-/* 41 */
+/* 54 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var collection = __webpack_require__(14);
+	  var collection = math.collection;
 
 	  /**
 	   * Divide two matrices element wise. The function accepts both matrices and
@@ -7342,14 +11474,14 @@
 
 
 /***/ },
-/* 42 */
+/* 55 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
-	      collection = __webpack_require__(14);
+	  var util = __webpack_require__(174),
+	      collection = math.collection;
 
 	  /**
 	   * Multiply two matrices element wise. The function accepts both matrices and
@@ -7393,14 +11525,14 @@
 
 
 /***/ },
-/* 43 */
+/* 56 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
-	      collection = __webpack_require__(14);
+	  var util = __webpack_require__(174),
+	      collection = math.collection;
 
 	  /**
 	   * Calculates the power of x to y element wise.
@@ -7441,18 +11573,18 @@
 
 
 /***/ },
-/* 44 */
+/* 57 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
-	      Matrix = __webpack_require__(10),
-	      collection = __webpack_require__(14),
+	      Matrix = math.type.Matrix,
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -7522,17 +11654,17 @@
 
 
 /***/ },
-/* 45 */
+/* 58 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -7587,7 +11719,8 @@
 	    }
 
 	    if (isCollection(x)) {
-	      return collection.deepMap(x, fix);
+	      // deep map collection, skip zeros since fix(0) = 0
+	      return collection.deepMap(x, fix, true);
 	    }
 
 	    if (isBoolean(x) || x === null) {
@@ -7600,17 +11733,17 @@
 
 
 /***/ },
-/* 46 */
+/* 59 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -7665,7 +11798,8 @@
 	    }
 
 	    if (isCollection(x)) {
-	      return collection.deepMap(x, floor);
+	      // deep map collection, skip zeros since floor(0) = 0
+	      return collection.deepMap(x, floor, true);
 	    }
 
 	    if (isBoolean(x) || x === null) {
@@ -7678,16 +11812,16 @@
 
 
 /***/ },
-/* 47 */
+/* 60 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -7825,16 +11959,16 @@
 
 
 /***/ },
-/* 48 */
+/* 61 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -7987,17 +12121,17 @@
 
 
 /***/ },
-/* 49 */
+/* 62 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -8090,17 +12224,17 @@
 
 
 /***/ },
-/* 50 */
+/* 63 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -8178,16 +12312,16 @@
 
 
 /***/ },
-/* 51 */
+/* 64 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -8317,21 +12451,20 @@
 
 
 /***/ },
-/* 52 */
+/* 65 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function(math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
-	      Matrix = __webpack_require__(10),
+	      Matrix = math.type.Matrix,
 	      Unit = __webpack_require__(11),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
-	      array = util.array,
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
 	      isComplex = Complex.isComplex,
@@ -8383,7 +12516,7 @@
 	      }
 	      else if (isComplex(y)) {
 	        // number * complex
-	        return _multiplyComplex (new Complex(x, 0), y);
+	        return _multiplyComplex(new Complex(x, 0), y);
 	      }
 	      else if (isUnit(y)) {
 	        res = y.clone();
@@ -8395,11 +12528,11 @@
 	    if (isComplex(x)) {
 	      if (isNumber(y)) {
 	        // complex * number
-	        return _multiplyComplex (x, new Complex(y, 0));
+	        return _multiplyComplex(x, new Complex(y, 0));
 	      }
 	      else if (isComplex(y)) {
 	        // complex * complex
-	        return _multiplyComplex (x, y);
+	        return _multiplyComplex(x, y);
 	      }
 	    }
 
@@ -8429,7 +12562,7 @@
 	      }
 
 	      if (x instanceof BigNumber) {
-	        return x.times(y)
+	        return x.times(y);
 	      }
 
 	      // downgrade to Number
@@ -8445,99 +12578,25 @@
 	    }
 
 	    if (isArray(x)) {
-	      if (isArray(y)) {
-	        // array * array
-	        var sizeX = array.size(x);
-	        var sizeY = array.size(y);
-
-	        if (sizeX.length == 1) {
-	          if (sizeY.length == 1) {
-	            // vector * vector
-	            if (sizeX[0] != sizeY[0]) {
-	              throw new RangeError('Dimension mismatch in multiplication. ' +
-	                  'Length of A must match length of B ' +
-	                  '(A is ' + sizeX[0] +
-	                  ', B is ' + sizeY[0] + ', ' +
-	                  sizeX[0] + ' != ' + sizeY[0] + ')');
-	            }
-
-	            return _multiplyVectorVector(x, y);
-	          }
-	          else if (sizeY.length == 2) {
-	            // vector * matrix
-	            if (sizeX[0] != sizeY[0]) {
-	              throw new RangeError('Dimension mismatch in multiplication. ' +
-	                  'Length of A must match rows of B ' +
-	                  '(A is ' + sizeX[0] +
-	                  ', B is ' + sizeY[0] + 'x' + sizeY[1] + ', ' +
-	                  sizeX[0] + ' != ' + sizeY[0] + ')');
-	            }
-
-	            return _multiplyVectorMatrix(x, y);
-	          }
-	          else {
-	            throw new Error('Can only multiply a 1 or 2 dimensional matrix ' +
-	                '(B has ' + sizeY.length + ' dimensions)');
-	          }
-	        }
-	        else if (sizeX.length == 2) {
-	          if (sizeY.length == 1) {
-	            // matrix * vector
-	            if (sizeX[1] != sizeY[0]) {
-	              throw new RangeError('Dimension mismatch in multiplication. ' +
-	                  'Columns of A must match length of B ' +
-	                  '(A is ' + sizeX[0] + 'x' + sizeX[0] +
-	                  ', B is ' + sizeY[0] + ', ' +
-	                  sizeX[1] + ' != ' + sizeY[0] + ')');
-	            }
-
-	            return _multiplyMatrixVector(x, y);
-	          }
-	          else if (sizeY.length == 2) {
-	            // matrix * matrix
-	            if (sizeX[1] != sizeY[0]) {
-	              throw new RangeError('Dimension 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] + ', ' +
-	                  sizeX[1] + ' != ' + sizeY[0] + ')');
-	            }
-
-	            return _multiplyMatrixMatrix(x, y);
-	          }
-	          else {
-	            throw new Error('Can only multiply a 1 or 2 dimensional matrix ' +
-	                '(B has ' + sizeY.length + ' dimensions)');
-	          }
-	        }
-	        else {
-	          throw new Error('Can only multiply a 1 or 2 dimensional matrix ' +
-	              '(A has ' + sizeX.length + ' dimensions)');
-	        }
-	      }
-	      else if (y instanceof Matrix) {
-	        // array * matrix
-	        res = multiply(x, y.valueOf());
-	        return isArray(res) ? new Matrix(res) : res;
-	      }
-	      else {
-	        // array * scalar
-	        return collection.deepMap2(x, y, multiply);
-	      }
+	      // create dense matrix from array
+	      var m = math.matrix(x);
+	      // use optimized operations in matrix
+	      var r = m.multiply(y);
+	      // check result
+	      if (r instanceof Matrix) {
+	        // check we need to return a matrix
+	        if (y instanceof Matrix)
+	          return r;
+	        // output should be an array
+	        return r.valueOf();
+	      }
+	      // scalar
+	      return r;
 	    }
 
 	    if (x instanceof Matrix) {
-	      if (y instanceof Matrix) {
-	        // matrix * matrix
-	        res = multiply(x.valueOf(), y.valueOf());
-	        return isArray(res) ? new Matrix(res) : res;
-	      }
-	      else {
-	        // matrix * array
-	        // matrix * scalar
-	        res = multiply(x.valueOf(), y);
-	        return isArray(res) ? new Matrix(res) : res;
-	      }
+	      // use optimized matrix implementation
+	      return x.multiply(y);
 	    }
 
 	    if (isArray(y)) {
@@ -8545,8 +12604,12 @@
 	      return collection.deepMap2(x, y, multiply);
 	    }
 	    else if (y instanceof Matrix) {
+	      // adapter function
+	      var mf = function (v) {
+	        return multiply(x, v);
+	      };
 	      // scalar * matrix
-	      return new Matrix(collection.deepMap2(x, y.valueOf(), multiply));
+	      return collection.deepMap(y, mf, true);
 	    }
 
 	    if (isBoolean(x) || x === null) {
@@ -8560,112 +12623,6 @@
 	  };
 
 	  /**
-	   * Multiply two 2-dimensional matrices.
-	   * The size of the matrices is not validated.
-	   * @param {Array} x   A 2d matrix
-	   * @param {Array} y   A 2d matrix
-	   * @return {Array | Number} result
-	   * @private
-	   */
-	  function _multiplyMatrixMatrix(x, y) {
-	    // TODO: performance of matrix multiplication can be improved
-	    var res = [],
-	        rows = x.length,
-	        cols = y[0].length,
-	        num = x[0].length;
-
-	    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 = math.multiply(x[r][n], y[n][c]);
-	          result = (result === null) ? p : math.add(result, p);
-	        }
-	        res[r][c] = result;
-	      }
-	    }
-
-	    var isScalar = rows === 1 && cols === 1;
-	    return isScalar ? res[0][0] : res;
-	  }
-
-	  /**
-	   * Multiply a vector with a 2-dimensional matrix
-	   * The size of the matrices is not validated.
-	   * @param {Array} x   A vector
-	   * @param {Array} y   A 2d matrix
-	   * @return {Array | Number} result
-	   * @private
-	   */
-	  function _multiplyVectorMatrix(x, y) {
-	    // TODO: performance of matrix multiplication can be improved
-	    var res = [],
-	        rows = y.length,
-	        cols = y[0].length;
-
-	    for (var c = 0; c < cols; c++) {
-	      var result = null;
-	      for (var r = 0; r < rows; r++) {
-	        var p = math.multiply(x[r], y[r][c]);
-	        result = (r === 0) ? p : math.add(result, p);
-	      }
-	      res[c] = result;
-	    }
-
-	    return res.length === 1 ? res[0] : res;
-	  }
-
-	  /**
-	   * Multiply a 2-dimensional matrix with a vector
-	   * The size of the matrices is not validated.
-	   * @param {Array} x   A 2d matrix
-	   * @param {Array} y   A vector
-	   * @return {Array | Number} result
-	   * @private
-	   */
-	  function _multiplyMatrixVector(x, y) {
-	    // TODO: performance of matrix multiplication can be improved
-	    var res = [],
-	        rows = x.length,
-	        cols = x[0].length;
-
-	    for (var r = 0; r < rows; r++) {
-	      var result = null;
-	      for (var c = 0; c < cols; c++) {
-	        var p = math.multiply(x[r][c], y[c]);
-	        result = (c === 0) ? p : math.add(result, p);
-	      }
-	      res[r] = result;
-	    }
-
-	    return res.length === 1 ? res[0] : res;
-	  }
-
-	  /**
-	   * Multiply two vectors, calculate the dot product
-	   * The size of the matrices is not validated.
-	   * @param {Array} x   A vector
-	   * @param {Array} y   A vector
-	   * @return {Number} dotProduct
-	   * @private
-	   */
-	  function _multiplyVectorVector(x, y) {
-	    // TODO: performance of matrix multiplication can be improved
-	    var len = x.length;
-
-	    if (!len) {
-	      throw new Error('Cannot multiply two empty vectors');
-	    }
-
-	    var dot = 0;
-	    for (var i = 0; i < len; i++) {
-	      dot = math.add(dot, math.multiply(x[i], y[i]));
-	    }
-	    return dot;
-	  }
-
-	  /**
 	   * Multiply two complex numbers. x * y or multiply(x, y)
 	   * @param {Complex} x
 	   * @param {Complex} y
@@ -8748,20 +12705,17 @@
 
 
 /***/ },
-/* 53 */
+/* 66 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
-
-	    array = __webpack_require__(165),
+	  var util = __webpack_require__(174),
 
 	    BigNumber = math.type.BigNumber,
 	    Complex = __webpack_require__(7),
-	    Matrix = __webpack_require__(10),
-	    collection = __webpack_require__(14),
+	    Matrix = math.type.Matrix,
 
 	    isNumber = util.number.isNumber,
 	    isBoolean = util['boolean'].isBoolean,
@@ -8821,11 +12775,11 @@
 	      var re = Math.abs(x.re);
 	      var im = Math.abs(x.im);
 	      if (re >= im) {
-	        var x = im / re;
-	        return re * Math.sqrt(1 + x * x);
+	        var i = im / re;
+	        return re * Math.sqrt(1 + i * i);
 	      }
-	      var y = re / im;
-	      return im * Math.sqrt(1 + y * y);
+	      var j = re / im;
+	      return im * Math.sqrt(1 + j * j);
 	    }
 
 	    if (x instanceof BigNumber) {
@@ -8839,8 +12793,13 @@
 	    }
 
 	    if (isArray(x)) {
+	      // use matrix optimized operations
+	      return norm(math.matrix(x), p);
+	    }
+	    
+	    if (x instanceof Matrix) {
 	      // size
-	      var sizeX = array.size(x);
+	      var sizeX = x.size();
 	      // missing p
 	      if (p == null)
 	        p = 2;
@@ -8850,21 +12809,25 @@
 	        if (p === Number.POSITIVE_INFINITY || p === 'inf') {
 	          // norm(x, Infinity) = max(abs(x))
 	          var n;
-	          math.forEach(x, function (value) {
-	            var v = math.abs(value);
-	            if (!n || math.larger(v, n))
-	              n = v;
-	          });
+	          x.forEach(
+	            function (value) {
+	              var v = math.abs(value);
+	              if (!n || math.larger(v, n))
+	                n = v;
+	            },
+	            true);
 	          return n;
 	        }
 	        if (p === Number.NEGATIVE_INFINITY || p === '-inf') {
 	          // norm(x, -Infinity) = min(abs(x))
 	          var n;
-	          math.forEach(x, function (value) {
-	            var v = math.abs(value);
-	            if (!n || math.smaller(v, n))
-	              n = v;
-	          });
+	          x.forEach(
+	            function (value) {
+	              var v = math.abs(value);
+	              if (!n || math.smaller(v, n))
+	                n = v;
+	            },
+	            true);
 	          return n;
 	        }
 	        if (p === 'fro')
@@ -8874,9 +12837,11 @@
 	          if (!math.equal(p, 0)) {
 	            // norm(x, p) = sum(abs(xi) ^ p) ^ 1/p
 	            var n = 0;
-	            math.forEach(x, function (value) {
-	              n = math.add(math.pow(math.abs(value), p), n);
-	            });
+	            x.forEach(
+	              function (value) {
+	                n = math.add(math.pow(math.abs(value), p), n);
+	              },
+	              true);
 	            return math.pow(n, 1 / p);
 	          }
 	          return Number.POSITIVE_INFINITY;
@@ -8889,40 +12854,28 @@
 	        if (p == 1) {
 	          // norm(x) = the largest column sum
 	          var c = [];
-	          // loop rows
-	          for (var i = 0; i < x.length; i++) {
-	            var r = x[i];
-	            // loop columns
-	            for (var j = 0; j < r.length; j++) {
-	              c[j] = math.add(c[j] || 0, math.abs(r[j]));
-	            }
-	          }
+	          x.forEach(
+	            function (value, index) {
+	              var j = index[1];
+	              c[j] = math.add(c[j] || 0, math.abs(value));
+	            },
+	            true);
 	          return math.max(c);
 	        }
 	        if (p == Number.POSITIVE_INFINITY || p === 'inf') {
 	          // norm(x) = the largest row sum
-	          var n = 0;
-	          // loop rows
-	          for (var i = 0; i < x.length; i++) {
-	            var rs = 0;
-	            var r = x[i];
-	            // loop columns
-	            for (var j = 0; j < r.length; j++) {
-	              rs = math.add(rs, math.abs(r[j]));
-	            }
-	            if (math.larger(rs, n))
-	              n = rs;
-	          }
-	          return n;
+	          var r = [];
+	          x.forEach(
+	            function (value, index) {
+	              var i = index[0];
+	              r[i] = math.add(r[i] || 0, math.abs(value));
+	            },
+	            true);
+	          return math.max(r);
 	        }
 	        if (p === 'fro') {
 	          // norm(x) = sqrt(sum(diag(x'x)))
-	          var d = math.diag(math.multiply(math.transpose(x), x));
-	          var s = 0;
-	          math.forEach(d, function (value) {
-	            s = math.add(value, s);
-	          });
-	          return math.sqrt(s);
+	          return math.sqrt(x.transpose().multiply(x).trace());
 	        }
 	        if (p == 2) {
 	          // not implemented
@@ -8933,26 +12886,22 @@
 	      }
 	    }
 
-	    if (x instanceof Matrix) {
-	      return norm(x.valueOf(), p);
-	    }
-
 	    throw new math.error.UnsupportedTypeError('norm', x);
 	  };
 	};
 
 
 /***/ },
-/* 54 */
+/* 67 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171);
+	  var util = __webpack_require__(174);
 
 	  var BigNumber = math.type.BigNumber;
-	  var collection = __webpack_require__(14);
+	  var collection = math.collection;
 
 	  var isNumber = util.number.isNumber;
 	  var isBoolean = util['boolean'].isBoolean;
@@ -9142,22 +13091,21 @@
 
 
 /***/ },
-/* 55 */
+/* 68 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
-	      Matrix = __webpack_require__(10),
-	      collection = __webpack_require__(14),
-
+	      Matrix = math.type.Matrix,
+	      
 	      array = util.array,
 	      isNumber = util.number.isNumber,
-	      isBoolean = util['boolean'].isBoolean,
+	      isBoolean = util.boolean.isBoolean,
 	      isArray = Array.isArray,
 	      isInteger = util.number.isInteger,
 	      isComplex = Complex.isComplex;
@@ -9233,7 +13181,7 @@
 	        }
 	        else {
 	          // downgrade to number to do complex valued computation
-	          return pow(x.toNumber(), y.toNumber())
+	          return pow(x.toNumber(), y.toNumber());
 	        }
 	      }
 	      else {
@@ -9257,7 +13205,7 @@
 	        }
 	        else {
 	          // downgrade to number to do complex valued computation
-	          return pow(x.toNumber(), y.toNumber())
+	          return pow(x.toNumber(), y.toNumber());
 	        }
 	      }
 	      else {
@@ -9295,7 +13243,7 @@
 	      return res;
 	    }
 	    else if (x instanceof Matrix) {
-	      return new Matrix(pow(x.valueOf(), y));
+	      return math.matrix(pow(x.valueOf(), y));
 	    }
 
 	    if (isBoolean(x) || x === null) {
@@ -9326,17 +13274,17 @@
 
 
 /***/ },
-/* 56 */
+/* 69 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isInteger = util.number.isInteger,
@@ -9466,17 +13414,17 @@
 
 
 /***/ },
-/* 57 */
+/* 70 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      number = util.number,
 	      isNumber = util.number.isNumber,
@@ -9533,7 +13481,8 @@
 	    }
 
 	    if (isCollection(x)) {
-	      return collection.deepMap(x, sign);
+	      // deep map collection, skip zeros since sign(0) = 0
+	      return collection.deepMap(x, sign, true);
 	    }
 
 	    if (isBoolean(x) || x === null) {
@@ -9546,17 +13495,17 @@
 
 
 /***/ },
-/* 58 */
+/* 71 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -9639,7 +13588,8 @@
 	    }
 
 	    if (isCollection(x)) {
-	      return collection.deepMap(x, sqrt);
+	      // deep map collection, skip zeros since sqrt(0) = 0
+	      return collection.deepMap(x, sqrt, true);
 	    }
 
 	    if (isBoolean(x) || x === null) {
@@ -9652,17 +13602,17 @@
 
 
 /***/ },
-/* 59 */
+/* 72 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -9713,7 +13663,8 @@
 	    }
 
 	    if (isCollection(x)) {
-	      return collection.deepMap(x, square);
+	      // deep map collection, skip zeros since square(0) = 0
+	      return collection.deepMap(x, square, true);
 	    }
 
 	    if (isBoolean(x) || x === null) {
@@ -9726,19 +13677,19 @@
 
 
 /***/ },
-/* 60 */
+/* 73 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
-	      Matrix = __webpack_require__(10),
+	      Matrix = math.type.Matrix,
 	      Unit = __webpack_require__(11),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isBoolean = util['boolean'].isBoolean,
 	      isNumber = util.number.isNumber,
@@ -9886,18 +13837,18 @@
 
 
 /***/ },
-/* 61 */
+/* 74 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math, config) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
 	      Unit = __webpack_require__(11),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -9956,7 +13907,8 @@
 	    }
 
 	    if (isCollection(x)) {
-	      return collection.deepMap(x, unaryMinus);
+	      // deep map collection, skip zeros since unaryMinus(0) = 0
+	      return collection.deepMap(x, unaryMinus, true);
 	    }
 
 	    if (isBoolean(x) || isString(x) || x === null) {
@@ -9970,23 +13922,23 @@
 	  // TODO: function unary is renamed to unaryMinus since version 0.23.0. Cleanup some day
 	  math.unary = function unary() {
 	    throw new Error('Function unary is deprecated. Use unaryMinus instead.');
-	  }
+	  };
 	};
 
 
 /***/ },
-/* 62 */
+/* 75 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math, config) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
 	      Unit = __webpack_require__(11),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -10041,7 +13993,8 @@
 	    }
 
 	    if (isCollection(x)) {
-	      return collection.deepMap(x, unaryPlus);
+	      // deep map collection, skip zeros since unaryPlus(0) = 0
+	      return collection.deepMap(x, unaryPlus, true);
 	    }
 
 	    if (isBoolean(x) || isString(x) || x === null) {
@@ -10055,15 +14008,15 @@
 
 
 /***/ },
-/* 63 */
+/* 76 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math, config) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
-	      Matrix = __webpack_require__(10),
+	      Matrix = math.type.Matrix,
 	      BigNumber = math.type.BigNumber,
 
 	      isNumber = util.number.isNumber,
@@ -10189,7 +14142,7 @@
 	    else {
 	      res = [a, a ? lastx : 0, lasty];
 	    }
-	    return (config.matrix === 'array') ? res : new Matrix(res);
+	    return (config.matrix === 'array') ? res : math.matrix(res);
 	  }
 
 	  /**
@@ -10231,30 +14184,30 @@
 	    else {
 	      res = [a, !a.isZero() ? lastx : 0, lasty];
 	    }
-	    return (config.matrix === 'array') ? res : new Matrix(res);
+	    return (config.matrix === 'array') ? res : math.matrix(res);
 	  }
 	};
 
 
 /***/ },
-/* 64 */
+/* 77 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math, config) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
-	      Matrix = __webpack_require__(10),
+	      Matrix = math.type.Matrix,
 	      Unit = __webpack_require__(11),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isBoolean = util['boolean'].isBoolean,
 	      isInteger = util.number.isInteger,
 	      isNumber = util.number.isNumber,
 	      isCollection = collection.isCollection,
-
+	      
 	      bigBitAnd = util.bignumber.and;
 
 	  /**
@@ -10336,18 +14289,18 @@
 
 
 /***/ },
-/* 65 */
+/* 78 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math, config) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
-	      Matrix = __webpack_require__(10),
+	      Matrix = math.type.Matrix,
 	      Unit = __webpack_require__(11),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isBoolean = util['boolean'].isBoolean,
 	      isInteger = util.number.isInteger,
@@ -10409,18 +14362,18 @@
 
 
 /***/ },
-/* 66 */
+/* 79 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math, config) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
-	      Matrix = __webpack_require__(10),
+	      Matrix = math.type.Matrix,
 	      Unit = __webpack_require__(11),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isBoolean = util['boolean'].isBoolean,
 	      isInteger = util.number.isInteger,
@@ -10509,18 +14462,18 @@
 
 
 /***/ },
-/* 67 */
+/* 80 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math, config) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
-	      Matrix = __webpack_require__(10),
+	      Matrix = math.type.Matrix,
 	      Unit = __webpack_require__(11),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isBoolean = util['boolean'].isBoolean,
 	      isInteger = util.number.isInteger,
@@ -10608,18 +14561,18 @@
 
 
 /***/ },
-/* 68 */
+/* 81 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math, config) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
-	      Matrix = __webpack_require__(10),
+	      Matrix = math.type.Matrix,
 	      Unit = __webpack_require__(11),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isBoolean = util['boolean'].isBoolean,
 	      isInteger = util.number.isInteger,
@@ -10730,18 +14683,18 @@
 
 
 /***/ },
-/* 69 */
+/* 82 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math, config) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
-	      Matrix = __webpack_require__(10),
+	      Matrix = math.type.Matrix,
 	      Unit = __webpack_require__(11),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isBoolean = util['boolean'].isBoolean,
 	      isInteger = util.number.isInteger,
@@ -10854,17 +14807,17 @@
 
 
 /***/ },
-/* 70 */
+/* 83 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math, config) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
-	      Matrix = __webpack_require__(10),
+	      Matrix = math.type.Matrix,
 	      Unit = __webpack_require__(11),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isBoolean = util['boolean'].isBoolean,
 	      isInteger = util.number.isInteger,
@@ -10924,17 +14877,17 @@
 
 
 /***/ },
-/* 71 */
+/* 84 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -11001,17 +14954,17 @@
 
 
 /***/ },
-/* 72 */
+/* 85 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      object = util.object,
 	      isNumber = util.number.isNumber,
@@ -11076,17 +15029,17 @@
 
 
 /***/ },
-/* 73 */
+/* 86 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      object = util.object,
 	      isNumber = util.number.isNumber,
@@ -11153,17 +15106,17 @@
 
 
 /***/ },
-/* 74 */
+/* 87 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -11229,805 +15182,18 @@
 
 
 /***/ },
-/* 75 */
-/***/ function(module, exports, __webpack_require__) {
-
-	'use strict';
-
-	module.exports = function (math) {
-	  var util = __webpack_require__(171),
-
-	      // take the BigNumber instance the provided math.js instance
-	      BigNumber = math.type.BigNumber,
-	      collection = __webpack_require__(14),
-
-	      isCollection = collection.isCollection,
-	      isNumber = util.number.isNumber,
-	      isString = util.string.isString,
-	      isBoolean = util['boolean'].isBoolean;
-
-	  /**
-	   * Create a BigNumber, which can store numbers with arbitrary precision.
-	   * When a matrix is provided, all elements will be converted to BigNumber.
-	   *
-	   * Syntax:
-	   *
-	   *    math.bignumber(x)
-	   *
-	   * Examples:
-	   *
-	   *    0.1 + 0.2;                                  // returns Number 0.30000000000000004
-	   *    math.bignumber(0.1) + math.bignumber(0.2);  // returns BigNumber 0.3
-	   *
-	   *
-	   *    7.2e500;                                    // returns Number Infinity
-	   *    math.bignumber('7.2e500');                  // returns BigNumber 7.2e500
-	   *
-	   * See also:
-	   *
-	   *    boolean, complex, index, matrix, string, unit
-	   *
-	   * @param {Number | String | Array | Matrix | Boolean | null} [value]  Value for the big number,
-	   *                                                    0 by default.
-	   * @returns {BigNumber} The created bignumber
-	   */
-	  math.bignumber = function bignumber(value) {
-	    if (arguments.length > 1) {
-	      throw new math.error.ArgumentsError('bignumber', arguments.length, 0, 1);
-	    }
-
-	    if ((value instanceof BigNumber) || isNumber(value) || isString(value)) {
-	      return new BigNumber(value);
-	    }
-
-	    if (isBoolean(value) || value === null) {
-	      return new BigNumber(+value);
-	    }
-
-	    if (isCollection(value)) {
-	      return collection.deepMap(value, bignumber);
-	    }
-
-	    if (arguments.length == 0) {
-	      return new BigNumber(0);
-	    }
-
-	    throw new math.error.UnsupportedTypeError('bignumber', math['typeof'](value));
-	  };
-	};
-
-
-/***/ },
-/* 76 */
-/***/ function(module, exports, __webpack_require__) {
-
-	'use strict';
-
-	module.exports = function (math) {
-	  var util = __webpack_require__(171),
-
-	      BigNumber = math.type.BigNumber,
-	      collection = __webpack_require__(14),
-
-	      isCollection = collection.isCollection,
-	      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.
-	   * When value is a matrix, all elements will be converted to boolean.
-	   *
-	   * Syntax:
-	   *
-	   *    math.boolean(x)
-	   *
-	   * Examples:
-	   *
-	   *    math.boolean(0);     // returns false
-	   *    math.boolean(1);     // returns true
-	   *    math.boolean(-3);     // returns true
-	   *    math.boolean('true');     // returns true
-	   *    math.boolean('false');     // returns false
-	   *    math.boolean([1, 0, 1, 1]);     // returns [true, false, true, true]
-	   *
-	   * See also:
-	   *
-	   *    bignumber, complex, index, matrix, string, unit
-	   *
-	   * @param {String | Number | Boolean | Array | Matrix | null} value  A value of any type
-	   * @return {Boolean | Array | Matrix} The boolean value
-	   */
-	  math['boolean'] = function bool (value) {
-	    if (arguments.length != 1) {
-	      throw new math.error.ArgumentsError('boolean', arguments.length, 0, 1);
-	    }
-
-	    if (value === 'true' || value === true) {
-	      return true;
-	    }
-
-	    if (value === 'false' || value === false || value === null) {
-	      return false;
-	    }
-
-	    if (value instanceof Boolean) {
-	      return value == true;
-	    }
-
-	    if (isNumber(value)) {
-	      return (value !== 0);
-	    }
-
-	    if (value instanceof BigNumber) {
-	      return !value.isZero();
-	    }
-
-	    if (isString(value)) {
-	      // try case insensitive
-	      var lcase = value.toLowerCase();
-	      if (lcase === 'true') {
-	        return true;
-	      }
-	      else if (lcase === 'false') {
-	        return false;
-	      }
-
-	      // test whether value is a valid number
-	      var num = Number(value);
-	      if (value != '' && !isNaN(num)) {
-	        return (num !== 0);
-	      }
-	    }
-
-	    if (isCollection(value)) {
-	      return collection.deepMap(value, bool);
-	    }
-
-	    throw new SyntaxError(value.toString() + ' is no valid boolean');
-	  };
-	};
-
-
-/***/ },
-/* 77 */
-/***/ function(module, exports, __webpack_require__) {
-
-	'use strict';
-
-	module.exports = function (math) {
-	  var util = __webpack_require__(171),
-
-	      BigNumber = math.type.BigNumber,
-	      Complex = __webpack_require__(7),
-	      collection = __webpack_require__(14),
-
-	      isCollection = collection.isCollection,
-	      isNumber = util.number.isNumber,
-	      isString = util.string.isString,
-	      isComplex = Complex.isComplex;
-
-	  /**
-	   * Create a complex value or convert a value to a complex value.
-	   *
-	   * Syntax:
-	   *
-	   *     math.complex()                           // creates a complex value with zero
-	   *                                              // as real and imaginary part.
-	   *     math.complex(re : number, im : string)   // creates a complex value with provided
-	   *                                              // values for real and imaginary part.
-	   *     math.complex(re : number)                // creates a complex value with provided
-	   *                                              // real value and zero imaginary part.
-	   *     math.complex(complex : Complex)          // clones the provided complex value.
-	   *     math.complex(arg : string)               // parses a string into a complex value.
-	   *     math.complex(array : Array)              // converts the elements of the array
-	   *                                              // or matrix element wise into a
-	   *                                              // complex value.
-	   *     math.complex({re: number, im: number})   // creates a complex value with provided
-	   *                                              // values for real an imaginary part.
-	   *     math.complex({r: number, phi: number})   // creates a complex value with provided
-	   *                                              // polar coordinates
-	   *
-	   * Examples:
-	   *
-	   *    var a = math.complex(3, -4);     // a = Complex 3 - 4i
-	   *    a.re = 5;                        // a = Complex 5 - 4i
-	   *    var i = a.im;                    // Number -4;
-	   *    var b = math.complex('2 + 6i');  // Complex 2 + 6i
-	   *    var c = math.complex();          // Complex 0 + 0i
-	   *    var d = math.add(a, b);          // Complex 5 + 2i
-	   *
-	   * See also:
-	   *
-	   *    bignumber, boolean, index, matrix, number, string, unit
-	   *
-	   * @param {* | Array | Matrix} [args]
-	   *            Arguments specifying the real and imaginary part of the complex number
-	   * @return {Complex | Array | Matrix} Returns a complex value
-	   */
-	  math.complex = function complex(args) {
-	    switch (arguments.length) {
-	      case 0:
-	        // no parameters. Set re and im zero
-	        return new Complex(0, 0);
-
-	      case 1:
-	        // parse string into a complex number
-	        var arg = arguments[0];
-
-	        if (isNumber(arg)) {
-	          return new Complex(arg, 0);
-	        }
-
-	        if (arg instanceof BigNumber) {
-	          // convert to Number
-	          return new Complex(arg.toNumber(), 0);
-	        }
-
-	        if (isComplex(arg)) {
-	          // create a clone
-	          return arg.clone();
-	        }
-
-	        if (isString(arg)) {
-	          var c = Complex.parse(arg);
-	          if (c) {
-	            return c;
-	          }
-	          else {
-	            throw new SyntaxError('String "' + arg + '" is no valid complex number');
-	          }
-	        }
-
-	        if (isCollection(arg)) {
-	          return collection.deepMap(arg, complex);
-	        }
-
-	        if (typeof arg === 'object') {
-	          if('re' in arg && 'im' in arg) {
-	            return new Complex(arg.re, arg.im);
-	          } else if ('r' in arg && 'phi' in arg) {
-	            return Complex.fromPolar(arg.r, arg.phi);
-	          }
-	        }
-
-	        throw new TypeError('Two numbers, single string or an fitting object expected in function complex');
-
-	      case 2:
-	        // re and im provided
-	        var re = arguments[0],
-	            im = arguments[1];
-
-	        // convert re to number
-	        if (re instanceof BigNumber) {
-	          re = re.toNumber();
-	        }
-
-	        // convert im to number
-	        if (im instanceof BigNumber) {
-	          im = im.toNumber();
-	        }
-
-	        if (isNumber(re) && isNumber(im)) {
-	          return new Complex(re, im);
-	        }
-	        else {
-	          throw new TypeError('Two numbers or a single string expected in function complex');
-	        }
-
-	      default:
-	        throw new math.error.ArgumentsError('complex', arguments.length, 0, 2);
-	    }
-	  };
-	};
-
-
-/***/ },
-/* 78 */
-/***/ function(module, exports, __webpack_require__) {
-
-	'use strict';
-
-	module.exports = function (math) {
-	  var util = __webpack_require__(171),
-
-	      BigNumber = math.type.BigNumber,
-	      Index = __webpack_require__(9);
-
-	  /**
-	   * Create an index. An Index can store ranges having start, step, and end
-	   * for multiple dimensions.
-	   * Matrix.get, Matrix.set, and math.subset accept an Index as input.
-	   *
-	   * Syntax:
-	   *
-	   *     math.index(range1, range2, ...)
-	   *
-	   * Where:
-	   *
-	   * Each range can be any of:
-	   *
-	   * - An array [start, end]
-	   * - An array [start, end, step]
-	   * - A number
-	   * - An instance of `Range`
-	   *
-	   * The parameters start, end, and step must be integer numbers. Start and end
-	   * are zero based. The start of a range is included, the end is excluded.
-	   *
-	   * Examples:
-	   *
-	   *    var math = math.js
-	   *
-	   *    var b = [1, 2, 3, 4, 5];
-	   *    math.subset(b, math.index([1, 3]));     // returns [2, 3]
-	   *
-	   *    var a = math.matrix([[1, 2], [3, 4]]);
-	   *    a.subset(math.index(0, 1));             // returns 2
-	   *    a.subset(math.index(1, null));          // returns [3, 4]
-	   *
-	   * See also:
-	   *
-	   *    bignumber, boolean, complex, matrix, number, string, unit
-	   *
-	   * @param {...*} ranges   Zero or more ranges or numbers.
-	   * @return {Index}        Returns the created index
-	   */
-	  math.index = function(ranges) {
-	    // downgrade BigNumber to Number
-	    var args = Array.prototype.slice.apply(arguments).map(function (arg) {
-	      if (arg instanceof BigNumber) {
-	        return arg.toNumber();
-	      }
-	      else if (Array.isArray(arg)) {
-	        return arg.map(function (elem) {
-	          return (elem instanceof BigNumber) ? elem.toNumber() : elem;
-	        });
-	      }
-	      else {
-	        return arg;
-	      }
-	    });
-
-	    var res = new Index();
-	    Index.apply(res, args);
-	    return res;
-	  };
-	};
-
-
-/***/ },
-/* 79 */
-/***/ function(module, exports, __webpack_require__) {
-
-	'use strict';
-
-	module.exports = function (math) {
-	  var util = __webpack_require__(171),
-	      Matrix = __webpack_require__(10);
-
-	  /**
-	   * Create a Matrix. The function creates a new `math.type.Matrix` object from
-	   * an `Array`. A Matrix has utility functions to manipulate the data in the
-	   * matrix, like getting the size and getting or setting values in the matrix.
-	   *
-	   * Syntax:
-	   *
-	   *    math.matrix()      // creates an empty matrix
-	   *    math.matrix(data)  // creates a matrix with initial data.
-	   *
-	   * Examples:
-	   *
-	   *    var m = math.matrix([[1, 2], [3, 4]]);
-	   *    m.size();                        // Array [2, 2]
-	   *    m.resize([3, 2], 5);
-	   *    m.valueOf();                     // Array [[1, 2], [3, 4], [5, 5]]
-	   *    m.get([1, 0])                    // number 3
-	   *
-	   * See also:
-	   *
-	   *    bignumber, boolean, complex, index, number, string, unit
-	   *
-	   * @param {Array | Matrix} [data]    A multi dimensional array
-	   * @return {Matrix} The created matrix
-	   */
-	  math.matrix = function matrix(data) {
-	    if (arguments.length > 1) {
-	      throw new math.error.ArgumentsError('matrix', arguments.length, 0, 1);
-	    }
-
-	    return new Matrix(data);
-	  };
-	};
-
-
-/***/ },
-/* 80 */
-/***/ function(module, exports, __webpack_require__) {
-
-	'use strict';
-
-	module.exports = function (math) {
-	  var util = __webpack_require__(171);
-
-	  var BigNumber = math.type.BigNumber;
-	  var Unit = math.type.Unit;
-	  var collection = __webpack_require__(14);
-
-	  var isCollection = collection.isCollection;
-	  var isNumber = util.number.isNumber;
-	  var isBoolean = util['boolean'].isBoolean;
-	  var isString = util.string.isString;
-
-	  /**
-	   * Create a number or convert a string, boolean, or unit to a number.
-	   * When value is a matrix, all elements will be converted to number.
-	   *
-	   * Syntax:
-	   *
-	   *    math.number(value)
-	   *    math.number(unit, valuelessUnit)
-	   *
-	   * Examples:
-	   *
-	   *    math.number(2);                         // returns number 2
-	   *    math.number('7.2');                     // returns number 7.2
-	   *    math.number(true);                      // returns number 1
-	   *    math.number([true, false, true, true]); // returns [1, 0, 1, 1]
-	   *    math.number(math.unit('52cm'), 'm');    // returns 0.52
-	   *
-	   * See also:
-	   *
-	   *    bignumber, boolean, complex, index, matrix, string, unit
-	   *
-	   * @param {String | Number | Boolean | Array | Matrix | Unit | null} [value]  Value to be converted
-	   * @param {Unit | string} [valuelessUnit] A valueless unit, used to convert a unit to a number
-	   * @return {Number | Array | Matrix} The created number
-	   */
-	  math.number = function number (value, valuelessUnit) {
-	    switch (arguments.length) {
-	      case 0:
-	        return 0;
-
-	      case 1:
-	        if (isCollection(value)) {
-	          return collection.deepMap(value, number);
-	        }
-
-	        if (value instanceof BigNumber) {
-	          return value.toNumber();
-	        }
-
-	        if (isString(value)) {
-	          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;
-	        }
-
-	        if (isBoolean(value) || value === null) {
-	          return +value;
-	        }
-
-	        if (isNumber(value)) {
-	          return value;
-	        }
-
-	        if (value instanceof Unit) {
-	          throw new Error('Second argument with valueless unit expected');
-	        }
-
-	        throw new math.error.UnsupportedTypeError('number', math['typeof'](value));
-
-	      case 2:
-	        if (value instanceof Unit && isString(valuelessUnit) || valuelessUnit instanceof Unit) {
-	          return value.toNumber(valuelessUnit);
-	        }
-
-	        throw new math.error.UnsupportedTypeError('number', math['typeof'](value), math['typeof'](valuelessUnit));
-
-
-	      default:
-	        throw new math.error.ArgumentsError('number', arguments.length, 0, 1);
-	    }
-	  };
-	};
-
-
-/***/ },
-/* 81 */
-/***/ function(module, exports, __webpack_require__) {
-
-	'use strict';
-
-	module.exports = function (math) {
-	  var Parser = __webpack_require__(17);
-
-	  /**
-	   * Create a parser. The function creates a new `math.expression.Parser` object.
-	   *
-	   * Syntax:
-	   *
-	   *    math.parser()
-	   *
-	   * Examples:
-	   *
-	   *     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();
-	   *
-	   * See also:
-	   *
-	   *    eval, compile, parse
-	   *
-	   * @return {Parser} Parser
-	   */
-	  math.parser = function parser() {
-	    return new Parser(math);
-	  };
-	};
-
-
-/***/ },
-/* 82 */
-/***/ function(module, exports, __webpack_require__) {
-
-	'use strict';
-
-	module.exports = function (math) {
-	  /**
-	   * Wrap any value in a chain, allowing to perform chained operations on
-	   * the value.
-	   *
-	   * All methods available in the math.js library can be called upon the chain,
-	   * and then will be evaluated with the value itself as first argument.
-	   * The chain can be closed by executing `chain.done()`, which returns
-	   * the final value.
-	   *
-	   * The chain has a number of special functions:
-	   *
-	   * - `done()`     Finalize the chain and return the chain's value.
-	   * - `valueOf()`  The same as `done()`
-	   * - `toString()` Executes `math.format()` onto the chain's value, returning
-	   *                a string representation of the value.
-	   *
-	   * Syntax:
-	   *
-	   *    math.chain(value)
-	   *
-	   * Examples:
-	   *
-	   *     math.chain(3)
-	   *         .add(4)
-	   *         .subtract(2)
-	   *         .done();     // 5
-	   *
-	   *     math.chain( [[1, 2], [3, 4]] )
-	   *         .subset(math.index(0, 0), 8)
-	   *         .multiply(3)
-	   *         .done();     // [[24, 6], [9, 12]]
-	   *
-	   * @param {*} [value]   A value of any type on which to start a chained operation.
-	   * @return {math.chaining.Chain} The created chain
-	   */
-	  math.chain = function(value) {
-	    // TODO: check number of arguments
-	    return new math.chaining.Chain(value);
-	  };
-
-	  // TODO: deprecate math.select in v2.0
-	  math.select = function(value) {
-	    // give a warning once.
-	    if (console && typeof console.log === 'function') {
-	      console.log('WARNING: Function "select" is renamed to "chain". It will be deprecated in v2.0.')
-	    }
-
-	    // replace warning function with chain function
-	    math.select = math.chain;
-	    math.chaining.Chain.prototype['select'] = math.select;
-
-	    return math.chain(value);
-	  }
-	};
-
-
-/***/ },
-/* 83 */
-/***/ function(module, exports, __webpack_require__) {
-
-	'use strict';
-
-	module.exports = function (math) {
-	  var util = __webpack_require__(171),
-
-	      collection = __webpack_require__(14),
-
-	      number = util.number,
-	      isNumber = util.number.isNumber,
-	      isCollection = collection.isCollection;
-
-	  /**
-	   * Create a string or convert any object into a string.
-	   * Elements of Arrays and Matrices are processed element wise.
-	   *
-	   * Syntax:
-	   *
-	   *    math.string(value)
-	   *
-	   * Examples:
-	   *
-	   *    math.string(4.2);               // returns string '4.2'
-	   *    math.string(math.complex(3, 2); // returns string '3 + 2i'
-	   *
-	   *    var u = math.unit(5, 'km');
-	   *    math.string(u.to('m'));         // returns string '5000 m'
-	   *
-	   *    math.string([true, false]);     // returns ['true', 'false']
-	   *
-	   * See also:
-	   *
-	   *    bignumber, boolean, complex, index, matrix, number, unit
-	   *
-	   * @param {* | Array | Matrix | null} [value]  A value to convert to a string
-	   * @return {String | Array | Matrix} The created string
-	   */
-	  math.string = function string (value) {
-	    switch (arguments.length) {
-	      case 0:
-	        return '';
-
-	      case 1:
-	        if (isNumber(value)) {
-	          return number.format(value);
-	        }
-
-	        if (isCollection(value)) {
-	          return collection.deepMap(value, string);
-	        }
-
-	        if (value === null) {
-	          return 'null';
-	        }
-
-	        return value.toString();
-
-	      default:
-	        throw new math.error.ArgumentsError('string', arguments.length, 0, 1);
-	    }
-	  };
-	};
-
-
-/***/ },
-/* 84 */
-/***/ function(module, exports, __webpack_require__) {
-
-	'use strict';
-
-	module.exports = function (math) {
-	  var util = __webpack_require__(171),
-
-	      BigNumber = math.type.BigNumber,
-	      Unit = __webpack_require__(11),
-	      collection = __webpack_require__(14),
-
-	      isCollection = collection.isCollection,
-	      isString = util.string.isString;
-
-	  /**
-	   * Create a unit. Depending on the passed arguments, the function
-	   * will create and return a new math.type.Unit object.
-	   * When a matrix is provided, all elements will be converted to units.
-	   *
-	   * Syntax:
-	   *
-	   *     math.unit(unit : string)
-	   *     math.unit(value : number, unit : string)
-	   *
-	   * Examples:
-	   *
-	   *    var a = math.unit(5, 'cm');    // returns Unit 50 mm
-	   *    var b = math.unit('23 kg');    // returns Unit 23 kg
-	   *    a.to('m');                     // returns Unit 0.05 m
-	   *
-	   * See also:
-	   *
-	   *    bignumber, boolean, complex, index, matrix, number, string
-	   *
-	   * @param {* | Array | Matrix} args   A number and unit.
-	   * @return {Unit | Array | Matrix}    The created unit
-	   */
-	  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();
-	        }
-
-	        if (isString(arg)) {
-	          if (Unit.isValuelessUnit(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');
-	        }
-
-	        if (isCollection(args)) {
-	          return collection.deepMap(args, unit);
-	        }
-
-	        throw new TypeError('A string or a number and string expected in function unit');
-
-	      case 2:
-	        // a number and a unit
-
-	        if (arguments[0] instanceof BigNumber) {
-	          // convert value to number
-	          return new Unit(arguments[0].toNumber(), arguments[1]);
-	        }
-	        else {
-	          return new Unit(arguments[0], arguments[1]);
-	        }
-
-	      default:
-	        throw new math.error.ArgumentsError('unit', arguments.length, 1, 2);
-	    }
-	  };
-	};
-
-
-/***/ },
-/* 85 */
-/***/ function(module, exports, __webpack_require__) {
-
-	'use strict';
-
-	module.exports = function (math) {
-	  var util = __webpack_require__(171),
-
-	      BigNumber = math.type.BigNumber,
-	      Complex = __webpack_require__(7),
-	      Unit = __webpack_require__(11),
-	      collection = __webpack_require__(14),
+/* 88 */
+/***/ function(module, exports, __webpack_require__) {
+
+	'use strict';
+
+	module.exports = function (math) {
+	  var util = __webpack_require__(174),
+
+	      BigNumber = math.type.BigNumber,
+	      Complex = __webpack_require__(7),
+	      Unit = __webpack_require__(11),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -12128,18 +15294,18 @@
 
 
 /***/ },
-/* 86 */
+/* 89 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
 	      Unit = __webpack_require__(11),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -12203,18 +15369,18 @@
 
 
 /***/ },
-/* 87 */
+/* 90 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
 	      Unit = __webpack_require__(11),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -12309,18 +15475,18 @@
 
 
 /***/ },
-/* 88 */
+/* 91 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
 	      Unit = __webpack_require__(11),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -12397,17 +15563,17 @@
 
 
 /***/ },
-/* 89 */
+/* 92 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171);
+	  var util = __webpack_require__(174);
 
 	  var BigNumber = __webpack_require__(5);
-	  var Matrix = __webpack_require__(10);
-	  var collection = __webpack_require__(14);
+	  var Matrix = math.type.Matrix;
+	  var collection = math.collection;
 
 	  var object = util.object;
 	  var array = util.array;
@@ -12504,7 +15670,7 @@
 	      res = _concat(res, matrices.shift(), dim, 0);
 	    }
 
-	    return asMatrix ? new Matrix(res) : res;
+	    return asMatrix ? math.matrix(res) : res;
 	  };
 
 	  /**
@@ -12539,14 +15705,14 @@
 
 
 /***/ },
-/* 90 */
+/* 93 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function(math) {
-	  var array = __webpack_require__(165);
-	  var Matrix = __webpack_require__(10);
+	  var array = __webpack_require__(168);
+	  var Matrix = math.type.Matrix;
 
 	  /**
 	   * Calculate the cross product for two vectors in three dimensional space.
@@ -12580,15 +15746,15 @@
 	  math.cross = function cross(x, y) {
 	    if (x instanceof Matrix) {
 	      if (y instanceof Matrix) {
-	        return new Matrix(_cross(x.toArray(), y.toArray()));
+	        return math.matrix(_cross(x.toArray(), y.toArray()));
 	      }
 	      else if (Array.isArray(y)) {
-	        return new Matrix(_cross(x.toArray(), y));
+	        return math.matrix(_cross(x.toArray(), y));
 	      }
 	    }
 	    else if (Array.isArray(x)) {
 	      if (y instanceof Matrix) {
-	        return new Matrix(_cross(x, y.toArray()));
+	        return math.matrix(_cross(x, y.toArray()));
 	      }
 	      else if (Array.isArray(y)) {
 	        return _cross(x, y);
@@ -12624,15 +15790,15 @@
 
 
 /***/ },
-/* 91 */
+/* 94 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
-	      Matrix = __webpack_require__(10),
+	      Matrix = math.type.Matrix,
 
 	      object = util.object,
 	      string = util.string;
@@ -12672,7 +15838,7 @@
 	      size = x.size();
 	    }
 	    else if (x instanceof Array) {
-	      x = new Matrix(x);
+	      x = math.matrix(x);
 	      size = x.size();
 	    }
 	    else {
@@ -12785,20 +15951,22 @@
 
 
 /***/ },
-/* 92 */
+/* 95 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
-	      Matrix = __webpack_require__(10),
+	      Matrix = math.type.Matrix,
 
 	      object = util.object,
-	      isArray = util.array.isArray,
+	      array = util.array,
+	      isArray = array.isArray,
 	      isNumber = util.number.isNumber,
+	      isString = util.string.isString,
 	      isInteger = util.number.isInteger;
 
 	  /**
@@ -12812,7 +15980,9 @@
 	   * Syntax:
 	   *
 	   *     math.diag(X)
+	   *     math.diag(X, format)
 	   *     math.diag(X, k)
+	   *     math.diag(X, k, format)
 	   *
 	   * Examples:
 	   *
@@ -12832,67 +16002,122 @@
 	   * @param {Matrix | Array} x          A two dimensional matrix or a vector
 	   * @param {Number | BigNumber} [k=0]  The diagonal where the vector will be filled
 	   *                                    in or retrieved.
-	   * @returns {Matrix | Array} Diagonal matrix from input vector, or diagonal from input matrix.
+	   * @param {string} [format='dense']   The matrix storage format.
+	   *
+	   * @returns {Matrix | Array}          Diagonal matrix from input vector, or diagonal from input matrix.
 	   */
-	  math.diag = function diag (x, k) {
-	    var data, vector, i, iMax;
-
-	    if (arguments.length != 1 && arguments.length != 2) {
-	      throw new math.error.ArgumentsError('diag', arguments.length, 1, 2);
-	    }
-
-	    if (k) {
-	      // convert BigNumber to a number
-	      if (k instanceof BigNumber) k = k.toNumber();
-
-	      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;
-
-	    // check type of input
-	    var asArray;
-	    if (x instanceof Matrix) {
-	      asArray = false;
-	    }
-	    else if (isArray(x)) {
-	      // convert to matrix
-	      x = new Matrix(x);
-	      asArray = true;
-	    }
-	    else {
+	  math.diag = function diag (x, k, format) {
+	    if (arguments.length === 0 || arguments.length > 3) {
+	      throw new math.error.ArgumentsError('diag', arguments.length, 1, 3);
+	    }
+	    
+	    // process args
+	    switch (arguments.length) {
+	      case 1:
+	        // defaults
+	        k = 0;
+	        format = undefined;
+	        break;
+	      case 2:
+	        // check second arg
+	        if (isString(arguments[1])) {
+	          // use arg as format
+	          format = arguments[1];
+	          // defaults
+	          k = 0;
+	        }
+	        break;
+	    }
+	    
+	    // verify x
+	    if (!(x instanceof Matrix) && !isArray(x)) {
+	      // throw
 	      throw new TypeError ('First parameter in function diag must be a Matrix or Array');
 	    }
 
-	    var s = x.size();
+	    // convert BigNumber to a number if needed
+	    if (k instanceof BigNumber) 
+	      k = k.toNumber();
+
+	    // verify k
+	    if (!isNumber(k) || !isInteger(k)) {
+	      throw new TypeError ('Second parameter in function diag must be an integer');
+	    }
+	    
+	    // verify format
+	    if (format && !isString(format)) {
+	      // throw
+	      throw new TypeError ('Third parameter in function diag must be a String');
+	    }
+	    
+	    var kSuper = k > 0 ? k : 0;
+	    var kSub = k < 0 ? -k : 0;
+	    
+	    var s, defaultValue, vector, d, i, iMax;
+	    
+	    // process matrix
+	    if (x instanceof Matrix) {
+	      // matrix data
+	      d = x.valueOf();
+	      // set format if needed
+	      format = format || x.storage();
+	      // matrix size
+	      s = x.size();
+	    }
+	    else {
+	      // data (array)
+	      d = x;
+	      // get size    
+	      s = array.size(x);
+	    }
+	     
+	    // check we need to return a matrix
+	    if (format) {
+	      // check length
+	      if (s.length === 1) {
+	        // default value
+	        defaultValue = (d[0] instanceof BigNumber) ? new BigNumber(0) : 0;
+	        // matrix size
+	        var ms = [d.length + kSub, d.length + kSuper];
+	        // get matrix constructor
+	        var F = Matrix.storage(format);
+	        // create diagonal matrix
+	        return F.diagonal(ms, d, k, defaultValue);
+	      }
+	      // check a two dimensional matrix was provided
+	      if (s.length === 2) {
+	        // return kth diagonal
+	        vector = x.diagonal(k);
+	        // return matrix
+	        return math.matrix(vector, format);
+	      }
+	      throw new RangeError('Matrix for function diag must be 2 dimensional');
+	    }
+	    
+	    // process array length
 	    switch (s.length) {
 	      case 1:
-	        // x is a vector. create diagonal matrix
-	        vector = x.valueOf();
-	        var matrix = new Matrix();
-	        var defaultValue = (vector[0] instanceof BigNumber) ? new BigNumber(0) : 0;
-	        matrix.resize([vector.length + kSub, vector.length + kSuper], defaultValue);
-	        data = matrix.valueOf();
-	        iMax = vector.length;
+	        // default value
+	        defaultValue = (d[0] instanceof BigNumber) ? new BigNumber(0) : 0;
+	        // data
+	        var data = [];
+	        // resize array
+	        array.resize(data, [d.length + kSub, d.length + kSuper], defaultValue);
+	        // set diagonal
+	        iMax = d.length;
 	        for (i = 0; i < iMax; i++) {
-	          data[i + kSub][i + kSuper] = object.clone(vector[i]);
+	          data[i + kSub][i + kSuper] = object.clone(d[i]);
 	        }
-	        return asArray ? matrix.valueOf() : matrix;
+	        return data;
 
 	      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]);
+	          vector[i] = object.clone(d[i + kSub][i + kSuper]);
 	        }
-	        return asArray ? vector : new Matrix(vector);
+	        return vector;
 
 	      default:
 	        throw new RangeError('Matrix for function diag must be 2 dimensional');
@@ -12902,14 +16127,14 @@
 
 
 /***/ },
-/* 93 */
+/* 96 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function(math) {
-	  var array = __webpack_require__(165);
-	  var Matrix = __webpack_require__(10);
+	  var array = __webpack_require__(168);
+	  var Matrix = math.type.Matrix;
 
 	  /**
 	   * Calculate the dot product of two vectors. The dot product of
@@ -12983,20 +16208,22 @@
 
 
 /***/ },
-/* 94 */
+/* 97 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math, config) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
-	      Matrix = __webpack_require__(10),
-	      collection = __webpack_require__(14),
+	      Matrix = math.type.Matrix,
+	      collection = math.collection,
+	      array = util.array,
 
 	      isNumber = util.number.isNumber,
 	      isInteger = util.number.isInteger,
+	      isString = util.string.isString,
 	      isArray = Array.isArray;
 
 	  /**
@@ -13006,8 +16233,11 @@
 	   * Syntax:
 	   *
 	   *    math.eye(n)
+	   *    math.eye(n, format)
 	   *    math.eye(m, n)
+	   *    math.eye(m, n, format)
 	   *    math.eye([m, n])
+	   *    math.eye([m, n], format)
 	   *
 	   * Examples:
 	   *
@@ -13022,19 +16252,33 @@
 	   *    diag, ones, zeros, size, range
 	   *
 	   * @param {...Number | Matrix | Array} size   The size for the matrix
+	   * @param {string} [format]                   The Matrix storage format
+	   *
 	   * @return {Matrix | Array | Number} A matrix with ones on the diagonal.
 	   */
-	  math.eye = function eye (size) {
-	    var args = collection.argsToArray(arguments),
-	        asMatrix = (size instanceof Matrix) ? true :
-	        (isArray(size) ? false : (config.matrix === 'matrix'));
-
-
-	    if (args.length == 0) {
-	      // return an empty array
-	      return asMatrix ? new Matrix() : [];
-	    }
-	    else if (args.length == 1) {
+	  math.eye = function eye (size, format) {
+	    // process arguments
+	    var args = collection.argsToArray(arguments);    
+	    // matrix storage format
+	    var f;
+	    // check format was provided
+	    if (args.length > 0 && isString(args[args.length - 1])) {
+	      // set format
+	      f = args[args.length - 1];
+	      // re-process arguments, ignore last one
+	      args = collection.argsToArray(args.slice(0, args.length - 1));
+	    }
+	    else if (size instanceof Matrix) {
+	      // use matrix format
+	      f = size.storage();
+	    }
+	    else if (!isArray(size) && config.matrix === 'matrix') {
+	      // use default matrix format
+	      f = 'default';
+	    }
+
+	    // check a single arg was provided
+	    if (args.length == 1) {
 	      // change to a 2-dimensional square
 	      args[1] = args[0];
 	    }
@@ -13042,59 +16286,71 @@
 	      // error in case of an n-dimensional size
 	      throw new math.error.ArgumentsError('eye', args.length, 0, 2);
 	    }
-
-	    var rows = args[0],
-	        cols = args[1];
-
-	    if (rows instanceof BigNumber) rows = rows.toNumber();
-	    if (cols instanceof BigNumber) cols = cols.toNumber();
-
-	    if (!isNumber(rows) || !isInteger(rows) || rows < 1) {
-	      throw new Error('Parameters in function eye must be positive integers');
-	    }
-	    if (!isNumber(cols) || !isInteger(cols) || cols < 1) {
-	      throw new Error('Parameters in function eye must be positive integers');
-	    }
-
+	    
 	    // convert arguments from bignumber to numbers if needed
 	    var asBigNumber = false;
+	    // map arguments & validate
 	    args = args.map(function (value) {
+	      // check it is a big number
 	      if (value instanceof BigNumber) {
+	        // set flag
 	        asBigNumber = true;
-	        return value.toNumber();
-	      } else {
-	        return value;
+	        // convert it
+	        value = value.toNumber();
 	      }
+	      // validate arguments
+	      if (!isNumber(value) || !isInteger(value) || value < 0) {
+	        throw new Error('Parameters in function eye must be positive integers');
+	      } 
+	      return value;
 	    });
 
-	    // create the matrix
-	    var matrix = new Matrix();
+	    // one
 	    var one = asBigNumber ? new BigNumber(1) : 1;
+	    // default value
 	    var defaultValue = asBigNumber ? new BigNumber(0) : 0;
-	    matrix.resize(args, defaultValue);
-
-	    // 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] = one;
-	    }
-
-	    return asMatrix ? matrix : matrix.valueOf();
+
+	    // check we need to return a matrix
+	    if (f) {      
+	      // check dimensions
+	      if (args.length === 0) {
+	        // empty matrix
+	        return math.matrix(f);
+	      }
+	      // get matrix storage constructor
+	      var F = Matrix.storage(f);
+	      // create diagonal matrix (use optimized implementation for storage format)
+	      return F.diagonal(args, one, 0, defaultValue);
+	    }
+
+	    // empty array
+	    var res = [];
+	    // check we need to resize array
+	    if (args.length > 0) {
+	      // resize array
+	      res = array.resize(res, args, defaultValue);
+	      // fill in ones on the diagonal
+	      var minimum = math.min(args);
+	      // fill diagonal
+	      for (var d = 0; d < minimum; d++) {
+	        res[d][d] = one;
+	      }
+	    }
+	    return res;
 	  };
 	};
 
 
 /***/ },
-/* 95 */
+/* 98 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math, config) {
-	  var util = __webpack_require__(171);
+	  var util = __webpack_require__(174);
 
-	  var Matrix = __webpack_require__(10);
+	  var Matrix = math.type.Matrix;
 
 	  var object = util.object;
 	  var array = util.array;
@@ -13126,7 +16382,7 @@
 	    if (x instanceof Matrix) {
 	      var clone = object.clone(x.toArray());
 	      var flat = array.flatten(clone);
-	      return new Matrix(flat);
+	      return math.matrix(flat);
 	    }
 
 	    if (isArray(x)) {
@@ -13139,14 +16395,14 @@
 
 
 /***/ },
-/* 96 */
+/* 99 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171);
-	  var Matrix = __webpack_require__(10);
+	  var util = __webpack_require__(174);
+	  var Matrix = math.type.Matrix;
 
 	  /**
 	   * Calculate the inverse of a square matrix.
@@ -13182,7 +16438,7 @@
 	        // vector
 	        if (size[0] == 1) {
 	          if (x instanceof Matrix) {
-	            return new Matrix([
+	            return math.matrix([
 	              math._divide(1, x.valueOf()[0])
 	            ]);
 	          }
@@ -13203,8 +16459,9 @@
 	        var cols = size[1];
 	        if (rows == cols) {
 	          if (x instanceof Matrix) {
-	            return new Matrix(
-	                _inv(x.valueOf(), rows, cols)
+	            return math.matrix(
+	              _inv(x.valueOf(), rows, cols),
+	              x.storage()
 	            );
 	          }
 	          else {
@@ -13337,20 +16594,22 @@
 
 
 /***/ },
-/* 97 */
+/* 100 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math, config) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
-	      Matrix = __webpack_require__(10),
-	      collection = __webpack_require__(14),
+	      Matrix = math.type.Matrix,
+	      collection = math.collection,
 
 	      array = util.array,
-
+	      isNumber = util.number.isNumber,
+	      isInteger = util.number.isInteger,
+	      isString = util.string.isString,
 	      isArray = Array.isArray;
 
 	  /**
@@ -13360,14 +16619,19 @@
 	   * Syntax:
 	   *
 	   *    math.ones(m)
+	   *    math.ones(m, format)
 	   *    math.ones(m, n)
+	   *    math.ones(m, n, format)
 	   *    math.ones([m, n])
+	   *    math.ones([m, n], format)
 	   *    math.ones([m, n, p, ...])
+	   *    math.ones([m, n, p, ...], format)
 	   *
 	   * Examples:
 	   *
 	   *    math.ones(3);                   // returns [1, 1, 1]
 	   *    math.ones(3, 2);                // returns [[1, 1], [1, 1], [1, 1]]
+	   *    math.ones(3, 2, 'dense');       // returns Dense Matrix [[1, 1], [1, 1], [1, 1]]
 	   *
 	   *    var A = [[1, 2, 3], [4, 5, 6]];
 	   *    math.zeros(math.size(A));       // returns [[1, 1, 1], [1, 1, 1]]
@@ -13377,54 +16641,87 @@
 	   *    zeros, eye, size, range
 	   *
 	   * @param {...Number | Array} size    The size of each dimension of the matrix
+	   * @param {string} [format]           The Matrix storage format
+	   *
 	   * @return {Array | Matrix | Number}  A matrix filled with ones
 	   */
-	  math.ones = function ones (size) {
-	    var args = collection.argsToArray(arguments);
-	    var asMatrix = (size instanceof Matrix) ? true :
-	        (isArray(size) ? false : (config.matrix === 'matrix'));
-
-	    if (args.length == 0) {
-	      // output an empty matrix
-	      return asMatrix ? new Matrix() : [];
-	    }
-	    else {
-	      // output an array or matrix
-
-	      // convert arguments from bignumber to numbers if needed
-	      var asBigNumber = false;
-	      args = args.map(function (value) {
-	        if (value instanceof BigNumber) {
-	          asBigNumber = true;
-	          return value.toNumber();
-	        } else {
-	          return value;
-	        }
-	      });
-
-	      // resize the matrix
-	      var res = [];
-	      var defaultValue = asBigNumber ? new BigNumber(1) : 1;
-	      res = array.resize(res, args, defaultValue);
-
-	      return asMatrix ? new Matrix(res) : res;
-	    }
+	  math.ones = function ones (size, format) {
+	    // process arguments
+	    var args = collection.argsToArray(arguments);    
+	    // matrix storage format
+	    var f;
+	    // check format was provided
+	    if (args.length > 0 && isString(args[args.length - 1])) {
+	      // set format
+	      f = args[args.length - 1];
+	      // re-process arguments, ignore last one
+	      args = collection.argsToArray(args.slice(0, args.length - 1));
+	    }
+	    else if (size instanceof Matrix) {
+	      // use matrix format
+	      f = size.storage();
+	    }
+	    else if (!isArray(size) && config.matrix === 'matrix') {
+	      // use default matrix format
+	      f = 'default';
+	    }
+
+	    // convert arguments from bignumber to numbers if needed
+	    var asBigNumber = false;
+	    // map arguments & validate
+	    args = args.map(function (value) {
+	      // check it is a big number
+	      if (value instanceof BigNumber) {
+	        // set flag
+	        asBigNumber = true;
+	        // convert it
+	        value = value.toNumber();
+	      }
+	      // validate arguments
+	      if (!isNumber(value) || !isInteger(value) || value < 0) {
+	        throw new Error('Parameters in function eye must be positive integers');
+	      } 
+	      return value;
+	    });
+	    
+	    // default value
+	    var defaultValue = asBigNumber ? new BigNumber(1) : 1;
+
+	    // check we need to return a matrix
+	    if (f) {
+	      // create empty matrix
+	      var m = math.matrix(f);
+	      // check we need to resize matrix
+	      if (args.length > 0) {
+	        // resize it to correct size
+	        return m.resize(args, defaultValue);
+	      }
+	      return m;
+	    }
+	    // empty array
+	    var res = [];
+	    // check we need to resize array
+	    if (args.length > 0) {
+	      // resize array
+	      return array.resize(res, args, defaultValue);
+	    }
+	    return res;
 	  };
 	};
 
 
 /***/ },
-/* 98 */
+/* 101 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math, config) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
-	      Matrix = __webpack_require__(10),
-	      collection = __webpack_require__(14),
+	      Matrix = math.type.Matrix,
+	      collection = math.collection,
 
 	      isBoolean = util['boolean'].isBoolean,
 	      isString = util.string.isString,
@@ -13564,7 +16861,7 @@
 	    var array = fn(start, end, step);
 
 	    // return as array or matrix
-	    return (config.matrix === 'array') ? array : new Matrix(array);
+	    return (config.matrix === 'array') ? array : math.matrix(array);
 	  };
 
 	  /**
@@ -13740,16 +17037,16 @@
 
 
 /***/ },
-/* 99 */
+/* 102 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math, config) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
-	      Matrix = __webpack_require__(10),
+	      Matrix = math.type.Matrix,
 
 	      array = util.array,
 	      clone = util.object.clone,
@@ -13790,11 +17087,6 @@
 	      throw new math.error.ArgumentsError('resize', arguments.length, 2, 3);
 	    }
 
-	    var asMatrix = (x instanceof Matrix) ? true : isArray(x) ? false : (config.matrix !== 'array');
-
-	    if (x instanceof Matrix) {
-	      x = x.valueOf(); // get Array
-	    }
 	    if (size instanceof Matrix) {
 	      size = size.valueOf(); // get Array
 	    }
@@ -13805,29 +17097,38 @@
 	        return (value instanceof BigNumber) ? value.toNumber() : value;
 	      });
 	    }
-
+	    
+	    // check x is a Matrix
+	    if (x instanceof Matrix) {
+	      // use optimized matrix implementation, return copy
+	      return x.resize(size, defaultValue, true);
+	    }
+	    
 	    if (isString(x)) {
+	      // resize string
 	      return _resizeString(x, size, defaultValue);
 	    }
+	    
+	    // check result should be a matrix
+	    var asMatrix = isArray(x) ? false : (config.matrix !== 'array');
+
+	    if (size.length == 0) {
+	      // output a scalar
+	      while (isArray(x)) {
+	        x = x[0];
+	      }
+
+	      return clone(x);
+	    }
 	    else {
-	      if (size.length == 0) {
-	        // output a scalar
-	        while (isArray(x)) {
-	          x = x[0];
-	        }
-
-	        return clone(x);
-	      }
-	      else {
-	        // output an array/matrix
-	        if (!isArray(x)) {
-	          x = [x];
-	        }
-	        x = clone(x);
-
-	        var res = array.resize(x, size, defaultValue);
-	        return asMatrix ? new Matrix(res) : res;
-	      }
+	      // output an array/matrix
+	      if (!isArray(x)) {
+	        x = [x];
+	      }
+	      x = clone(x);
+
+	      var res = array.resize(x, size, defaultValue);
+	      return asMatrix ? math.matrix(res) : res;
 	    }
 	  };
 
@@ -13875,18 +17176,18 @@
 
 
 /***/ },
-/* 100 */
+/* 103 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math, config) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
 	      Unit = __webpack_require__(11),
-	      Matrix = __webpack_require__(10),
+	      Matrix = math.type.Matrix,
 
 	      array = util.array,
 	      isNumber = util.number.isNumber,
@@ -13927,11 +17228,11 @@
 
 	    if (isNumber(x) || isComplex(x) || isUnit(x) || isBoolean(x) ||
 	        x == null || x instanceof BigNumber) {
-	      return asArray ? [] : new Matrix([]);
+	      return asArray ? [] : math.matrix([]);
 	    }
 
 	    if (isString(x)) {
-	      return asArray ? [x.length] : new Matrix([x.length]);
+	      return asArray ? [x.length] : math.matrix([x.length]);
 	    }
 
 	    if (Array.isArray(x)) {
@@ -13939,7 +17240,7 @@
 	    }
 
 	    if (x instanceof Matrix) {
-	      return new Matrix(x.size());
+	      return math.matrix(x.size());
 	    }
 
 	    throw new math.error.UnsupportedTypeError('size', math['typeof'](x));
@@ -13948,15 +17249,15 @@
 
 
 /***/ },
-/* 101 */
+/* 104 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
-	      Matrix = __webpack_require__(10),
+	      Matrix = math.type.Matrix,
 
 	      object = util.object,
 	      array = util.array,
@@ -14001,7 +17302,7 @@
 	    }
 	    else if (x instanceof Matrix) {
 	      var res = array.squeeze(x.toArray());
-	      return isArray(res) ? new Matrix(res) : res;
+	      return isArray(res) ? math.matrix(res) : res;
 	    }
 	    else {
 	      // scalar
@@ -14012,15 +17313,16 @@
 
 
 /***/ },
-/* 102 */
+/* 105 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
-	module.exports = function (math) {
-	  var util = __webpack_require__(171),
-
-	      Matrix = __webpack_require__(10),
+	module.exports = function (math, config) {
+
+	  var util = __webpack_require__(174),
+
+	      Matrix = math.type.Matrix,
 	      Index = __webpack_require__(9),
 
 	      array = util.array,
@@ -14058,7 +17360,7 @@
 	   *                                          If not provided, the subset is returned
 	   * @param {*} [defaultValue=undefined]      Default value, filled in on new entries when
 	   *                                          the matrix is resized. If not provided,
-	   *                                          new matrix elements will be left undefined.
+	   *                                          math.matrix elements will be left undefined.
 	   * @return {Array | Matrix | String} Either the retrieved subset or the updated matrix.
 	   */
 	  math.subset = function subset (matrix, index, replacement, defaultValue) {
@@ -14088,7 +17390,7 @@
 	    var m, subset;
 
 	    if (isArray(value)) {
-	      m = new Matrix(value);
+	      m = math.matrix(value);
 	      subset = m.subset(index);           // returns a Matrix
 	      return subset && subset.valueOf();  // return an Array (like the input)
 	    }
@@ -14142,7 +17444,7 @@
 	   * @param {Array | Matrix | *} replacement
 	   * @param {*} [defaultValue=0]      Default value, filled in on new entries when
 	   *                                  the matrix is resized. If not provided,
-	   *                                  new matrix elements will be filled with zeros.
+	   *                                  math.matrix elements will be filled with zeros.
 	   * @returns {*} result
 	   * @private
 	   */
@@ -14150,7 +17452,7 @@
 	    var m;
 
 	    if (isArray(value)) {
-	      m = new Matrix(math.clone(value));
+	      m = math.matrix(math.clone(value));
 	      m.subset(index, replacement, defaultValue);
 	      return m.valueOf();
 	    }
@@ -14229,17 +17531,18 @@
 
 
 /***/ },
-/* 103 */
+/* 106 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
-	      Matrix = __webpack_require__(10),
+	      Matrix = math.type.Matrix,
 
 	      object = util.object,
+	      array = util.array,
 	      string = util.string;
 
 	  /**
@@ -14266,6 +17569,7 @@
 	   *    diag
 	   *
 	   * @param {Array | Matrix} x  A matrix
+	   *
 	   * @return {Number} The trace of `x`
 	   */
 	  math.trace = function trace (x) {
@@ -14273,13 +17577,17 @@
 	      throw new math.error.ArgumentsError('trace', arguments.length, 1);
 	    }
 
+	    // check x is a matrix
+	    if (x instanceof Matrix) {
+	      // use optimized operation for the matrix storage format
+	      return x.trace();
+	    }
+	    
+	    // size
 	    var size;
-	    if (x instanceof Matrix) {
-	      size = x.size();
-	    }
-	    else if (x instanceof Array) {
-	      x = new Matrix(x);
-	      size = x.size();
+	    if (x instanceof Array) {
+	      // calculate sixe
+	      size = array.size(x);
 	    }
 	    else {
 	      // a scalar
@@ -14294,58 +17602,46 @@
 	      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) + ')');
-	        }
+	          // clone value
+	          return object.clone(x[0]);
+	        }
+	        throw new RangeError('Array must be square (size: ' + string.format(size) + ')');
 
 	      case 2:
 	        // two dimensional array
 	        var rows = size[0];
 	        var cols = size[1];
+	        // check array is square
 	        if (rows == cols) {
-	          return _trace(x.clone().valueOf());
-	        }
-	        else {
-	          throw new RangeError('Matrix must be square ' +
-	              '(size: ' + string.format(size) + ')');
-	        }
+	          // diagonal sum
+	          var sum = 0;
+	          // loop diagonal
+	          for (var i = 0; i < x.length; i++) {
+	            // sum
+	            sum = math.add(sum, x[i][i]);
+	          }
+	          return sum;
+	        }
+	        throw new RangeError('Array must be square (size: ' + string.format(size) + ')');
 
 	      default:
 	        // multi dimensional array
-	        throw new RangeError('Matrix must be two dimensional ' +
-	            '(size: ' + string.format(size) + ')');
+	        throw new RangeError('Matrix must be two dimensional (size: ' + string.format(size) + ')');
 	    }
 	  };
-
-	  /**
-	   * Calculate the trace of a matrix
-	   * @param {Array[]} matrix  A square, two dimensional matrix
-	   * @returns {Number} trace
-	   * @private
-	   */
-	  function _trace (matrix) {
-	    var sum = 0;
-	    for (var i = 0; i < matrix.length; i++) {
-	        sum = math.add(sum, matrix[i][i]);
-	    }
-	    return sum;
-	  }
 	};
 
 
 /***/ },
-/* 104 */
+/* 107 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
-	      Matrix = __webpack_require__(10),
+	      Matrix = math.type.Matrix,
 
 	      object = util.object,
 	      string = util.string;
@@ -14386,10 +17682,14 @@
 	        return object.clone(x);
 
 	      case 2:
+	        // check it is a matrix
+	        if (x instanceof Matrix) {
+	          // use optimized matrix implementation if available
+	          return x.transpose();
+	        }
 	        // two dimensional array
 	        var rows = size[1],
 	            cols = size[0],
-	            asMatrix = (x instanceof Matrix),
 	            data = x.valueOf(),
 	            transposed = [],
 	            transposedRow,
@@ -14408,7 +17708,7 @@
 	          }
 	        }
 
-	        return asMatrix ? new Matrix(transposed) : transposed;
+	        return transposed;
 
 	      default:
 	        // multi dimensional array
@@ -14420,19 +17720,22 @@
 
 
 /***/ },
-/* 105 */
+/* 108 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math, config) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
-	      Matrix = __webpack_require__(10),
-	      collection = __webpack_require__(14),
+	      Matrix = math.type.Matrix,
+	      collection = math.collection,
 
 	      array = util.array,
+	      isNumber = util.number.isNumber,
+	      isInteger = util.number.isInteger,
+	      isString = util.string.isString,
 	      isArray = Array.isArray;
 
 	  /**
@@ -14442,14 +17745,17 @@
 	   * Syntax:
 	   *
 	   *    math.zeros(m)
+	   *    math.zeros(m, format)
 	   *    math.zeros(m, n)
+	   *    math.zeros(m, n, format)
 	   *    math.zeros([m, n])
-	   *    math.zeros([m, n, p, ...])
+	   *    math.zeros([m, n], format)
 	   *
 	   * Examples:
 	   *
 	   *    math.zeros(3);                  // returns [0, 0, 0]
 	   *    math.zeros(3, 2);               // returns [[0, 0], [0, 0], [0, 0]]
+	   *    math.zeros(3, 'dense');         // returns [0, 0, 0]
 	   *
 	   *    var A = [[1, 2, 3], [4, 5, 6]];
 	   *    math.zeros(math.size(A));       // returns [[0, 0, 0], [0, 0, 0]]
@@ -14459,53 +17765,86 @@
 	   *    ones, eye, size, range
 	   *
 	   * @param {...Number | Array} size    The size of each dimension of the matrix
-	   * @return {Array | Matrix | Number}  A matrix filled with zeros
+	   * @param {string} [format]           The Matrix storage format
+	   *
+	   * @return {Array | Matrix}           A matrix filled with zeros
 	   */
 	  math.zeros = function zeros (size) {
-	    var args = collection.argsToArray(arguments);
-	    var asMatrix = (size instanceof Matrix) ? true :
-	        (isArray(size) ? false : (config.matrix === 'matrix'));
-
-	    if (args.length == 0) {
-	      // output an empty matrix
-	      return asMatrix ? new Matrix() : [];
-	    }
-	    else {
-	      // output an array or matrix
-
-	      // convert arguments from bignumber to numbers if needed
-	      var asBigNumber = false;
-	      args = args.map(function (value) {
-	        if (value instanceof BigNumber) {
-	          asBigNumber = true;
-	          return value.toNumber();
-	        } else {
-	          return value;
-	        }
-	      });
-
-	      // resize the matrix
-	      var res = [];
-	      var defaultValue = asBigNumber ? new BigNumber(0) : 0;
-	      res = array.resize(res, args, defaultValue);
-
-	      return asMatrix ? new Matrix(res) : res;
-	    }
+	    // process arguments
+	    var args = collection.argsToArray(arguments);    
+	    // matrix storage format
+	    var f;
+	    // check format was provided
+	    if (args.length > 0 && isString(args[args.length - 1])) {
+	      // set format
+	      f = args[args.length - 1];
+	      // re-process arguments, ignore last one
+	      args = collection.argsToArray(args.slice(0, args.length - 1));
+	    }
+	    else if (size instanceof Matrix) {
+	      // use matrix format
+	      f = size.storage();
+	    }
+	    else if (!isArray(size) && config.matrix === 'matrix') {
+	      // use default matrix format
+	      f = 'default';
+	    }
+
+	    // convert arguments from bignumber to numbers if needed
+	    var asBigNumber = false;
+	    // map arguments & validate
+	    args = args.map(function (value) {
+	      // check it is a big number
+	      if (value instanceof BigNumber) {
+	        // set flag
+	        asBigNumber = true;
+	        // convert it
+	        value = value.toNumber();
+	      }
+	      // validate arguments
+	      if (!isNumber(value) || !isInteger(value) || value < 0) {
+	        throw new Error('Parameters in function eye must be positive integers');
+	      } 
+	      return value;
+	    });
+	        
+	    // default value
+	    var defaultValue = asBigNumber ? new BigNumber(0) : 0;
+	    
+	    // check we need to return a matrix
+	    if (f) {
+	      // create empty matrix
+	      var m = math.matrix(f);
+	      // check we need to resize matrix
+	      if (args.length > 0) {
+	        // resize it to correct size
+	        return m.resize(args, defaultValue);
+	      }
+	      return m;
+	    }
+	    // empty array
+	    var res = [];
+	    // check we need to resize array
+	    if (args.length > 0) {
+	      // resize array
+	      return array.resize(res, args, defaultValue);
+	    }
+	    return res;
 	  };
 	};
 
 
 /***/ },
-/* 106 */
+/* 109 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math, config) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -14638,17 +17977,17 @@
 
 
 /***/ },
-/* 107 */
+/* 110 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math, config) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isBoolean = util['boolean'].isBoolean,
 	      isComplex = Complex.isComplex,
@@ -14832,13 +18171,13 @@
 
 
 /***/ },
-/* 108 */
+/* 111 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var distribution = __webpack_require__(333)(math);
+	  var distribution = __webpack_require__(336)(math);
 
 	  /**
 	   * Return a random number larger or equal to `min` and smaller than `max`
@@ -14875,13 +18214,13 @@
 
 
 /***/ },
-/* 109 */
+/* 112 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var distribution = __webpack_require__(333)(math);
+	  var distribution = __webpack_require__(336)(math);
 
 	  /**
 	   * Return a random integer number larger or equal to `min` and smaller than `max`
@@ -14918,13 +18257,13 @@
 
 
 /***/ },
-/* 110 */
+/* 113 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var distribution = __webpack_require__(333)(math);
+	  var distribution = __webpack_require__(336)(math);
 
 	  /**
 	   * Random pick a value from a one dimensional array.
@@ -14950,13 +18289,13 @@
 
 
 /***/ },
-/* 111 */
+/* 114 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 
@@ -15000,12 +18339,12 @@
 	      if (!isInteger(n) || n < 0) {
 	        throw new TypeError('Positive integer value expected in function permutations');
 	      }
-
+	      
 	      // Permute n objects
 	      if (arity == 1) {
 	        return math.factorial(n);
 	      }
-
+	      
 	      // Permute n objects, k at a time
 	      if (arity == 2) {
 	        if (isNumber(k)) {
@@ -15063,16 +18402,16 @@
 
 
 /***/ },
-/* 112 */
+/* 115 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isInteger = util.number.isInteger;
@@ -15160,18 +18499,18 @@
 
 
 /***/ },
-/* 113 */
+/* 116 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math, config) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
 	      Unit = __webpack_require__(11),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      nearlyEqual = util.number.nearlyEqual,
@@ -15290,13 +18629,13 @@
 
 
 /***/ },
-/* 114 */
+/* 117 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var collection = __webpack_require__(14),
+	  var collection = math.collection,
 
 	      isCollection = collection.isCollection,
 	      isArray = Array.isArray;
@@ -15375,18 +18714,18 @@
 
 
 /***/ },
-/* 115 */
+/* 118 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math, config) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
 	      Unit = __webpack_require__(11),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      nearlyEqual = util.number.nearlyEqual,
@@ -15539,18 +18878,18 @@
 
 
 /***/ },
-/* 116 */
+/* 119 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math, config) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
 	      Unit = __webpack_require__(11),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      nearlyEqual = util.number.nearlyEqual,
@@ -15666,18 +19005,18 @@
 
 
 /***/ },
-/* 117 */
+/* 120 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math, config) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
 	      Unit = __webpack_require__(11),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      nearlyEqual = util.number.nearlyEqual,
@@ -15794,18 +19133,18 @@
 
 
 /***/ },
-/* 118 */
+/* 121 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math, config) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
 	      Unit = __webpack_require__(11),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      nearlyEqual = util.number.nearlyEqual,
@@ -15921,18 +19260,18 @@
 
 
 /***/ },
-/* 119 */
+/* 122 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math, config) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
 	      Unit = __webpack_require__(11),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      nearlyEqual = util.number.nearlyEqual,
@@ -16048,18 +19387,18 @@
 
 
 /***/ },
-/* 120 */
+/* 123 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math, config) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
 	      Unit = __webpack_require__(11),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      nearlyEqual = util.number.nearlyEqual,
@@ -16211,14 +19550,14 @@
 
 
 /***/ },
-/* 121 */
+/* 124 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var Matrix = __webpack_require__(10),
-	      collection = __webpack_require__(14),
+	  var Matrix = math.type.Matrix,
+	      collection = math.collection,
 
 	      isCollection = collection.isCollection;
 
@@ -16306,14 +19645,14 @@
 
 
 /***/ },
-/* 122 */
+/* 125 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var Matrix = __webpack_require__(10),
-	      collection = __webpack_require__(14),
+	  var Matrix = math.type.Matrix,
+	      collection = math.collection,
 
 	      isCollection = collection.isCollection;
 
@@ -16401,18 +19740,18 @@
 
 
 /***/ },
-/* 123 */
+/* 126 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var Matrix = __webpack_require__(10),
-	      collection = __webpack_require__(14),
+	  var Matrix = math.type.Matrix,
+	      collection = math.collection,
 
 	      isCollection = collection.isCollection,
 
-	      size = __webpack_require__(165).size,
+	      size = __webpack_require__(168).size,
 	      isArray = Array.isArray;
 
 	  /**
@@ -16423,9 +19762,9 @@
 	   *
 	   * Syntax:
 	   *
-	   *     mean.mean(a, b, c, ...)
-	   *     mean.mean(A)
-	   *     mean.mean(A, dim)
+	   *     math.mean(a, b, c, ...)
+	   *     math.mean(A)
+	   *     math.mean(A, dim)
 	   *
 	   * Examples:
 	   *
@@ -16505,21 +19844,21 @@
 
 
 /***/ },
-/* 124 */
+/* 127 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var Matrix = __webpack_require__(10),
+	  var Matrix = math.type.Matrix,
 	      Unit = __webpack_require__(11),
 	      BigNumber = math.type.BigNumber,
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = __webpack_require__(3).isNumber,
 	      isCollection = collection.isCollection,
 
-	      flatten = __webpack_require__(165).flatten;
+	      flatten = __webpack_require__(168).flatten;
 
 	  /**
 	   * Compute the median of a matrix or a list with values. The values are
@@ -16532,8 +19871,8 @@
 	   *
 	   * Syntax:
 	   *
-	   *     mean.median(a, b, c, ...)
-	   *     mean.median(A)
+	   *     math.median(a, b, c, ...)
+	   *     math.median(A)
 	   *
 	   * Examples:
 	   *
@@ -16619,14 +19958,14 @@
 
 
 /***/ },
-/* 125 */
+/* 128 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var Matrix = __webpack_require__(10),
-	      collection = __webpack_require__(14),
+	  var Matrix = math.type.Matrix,
+	      collection = math.collection,
 
 	      isCollection = collection.isCollection;
 
@@ -16704,7 +20043,7 @@
 
 
 /***/ },
-/* 126 */
+/* 129 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
@@ -16764,14 +20103,14 @@
 
 
 /***/ },
-/* 127 */
+/* 130 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var Matrix = __webpack_require__(10),
-	      collection = __webpack_require__(14),
+	  var Matrix = math.type.Matrix,
+	      collection = math.collection,
 
 	      isCollection = collection.isCollection;
 
@@ -16847,18 +20186,18 @@
 
 
 /***/ },
-/* 128 */
+/* 131 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var Matrix = __webpack_require__(10),
+	  var Matrix = math.type.Matrix,
 	      BigNumber = math.type.BigNumber,
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isCollection = collection.isCollection,
-	      isString = __webpack_require__(205).isString,
+	      isString = __webpack_require__(175).isString,
 
 	      DEFAULT_NORMALIZATION = 'unbiased';
 
@@ -16991,17 +20330,17 @@
 
 
 /***/ },
-/* 129 */
+/* 132 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -17085,18 +20424,18 @@
 
 
 /***/ },
-/* 130 */
+/* 133 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
 	      Unit = __webpack_require__(11),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -17136,7 +20475,7 @@
 	      if (x >= 1) {
 	        return Math.log(Math.sqrt(x*x - 1) + x);
 	      }
-	      if (x <= -1) {
+	      if (x <= -1) { 
 	        return new Complex(Math.log(Math.sqrt(x*x - 1) - x), Math.PI);
 	      }
 	      return acosh(new Complex(x, 0));
@@ -17178,17 +20517,17 @@
 
 
 /***/ },
-/* 131 */
+/* 134 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -17266,18 +20605,18 @@
 
 
 /***/ },
-/* 132 */
+/* 135 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
 	      Unit = __webpack_require__(11),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -17360,17 +20699,17 @@
 
 
 /***/ },
-/* 133 */
+/* 136 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -17451,18 +20790,18 @@
 
 
 /***/ },
-/* 134 */
+/* 137 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
 	      Unit = __webpack_require__(11),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -17513,7 +20852,7 @@
 
 	      // acsch(z) = -i*asinh(1/z)
 	      var den = x.re*x.re + x.im*x.im;
-	      x = (den != 0)
+	      x = (den != 0) 
 	        ? new Complex(
 	            x.re / den,
 	           -x.im / den
@@ -17544,17 +20883,17 @@
 
 
 /***/ },
-/* 135 */
+/* 138 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -17633,18 +20972,18 @@
 
 
 /***/ },
-/* 136 */
+/* 139 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
 	      Unit = __webpack_require__(11),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -17733,17 +21072,17 @@
 
 
 /***/ },
-/* 137 */
+/* 140 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -17808,7 +21147,8 @@
 	    }
 
 	    if (isCollection(x)) {
-	      return collection.deepMap(x, asin);
+	      // deep map collection, skip zeros since asin(0) = 0
+	      return collection.deepMap(x, asin, true);
 	    }
 
 	    if (isBoolean(x) || x === null) {
@@ -17825,18 +21165,18 @@
 
 
 /***/ },
-/* 138 */
+/* 141 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
 	      Unit = __webpack_require__(11),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -17896,7 +21236,8 @@
 	    }
 
 	    if (isCollection(x)) {
-	      return collection.deepMap(x, asinh);
+	      // deep map collection, skip zeros since asinh(0) = 0
+	      return collection.deepMap(x, asinh, true);
 	    }
 
 	    if (isBoolean(x) || x === null) {
@@ -17913,17 +21254,17 @@
 
 
 /***/ },
-/* 139 */
+/* 142 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -17992,7 +21333,8 @@
 	    }
 
 	    if (isCollection(x)) {
-	      return collection.deepMap(x, atan);
+	      // deep map collection, skip zeros since atan(0) = 0
+	      return collection.deepMap(x, atan, true);
 	    }
 
 	    if (isBoolean(x) || x === null) {
@@ -18009,22 +21351,24 @@
 
 
 /***/ },
-/* 140 */
+/* 143 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
 	      isComplex = Complex.isComplex,
-	      isCollection = collection.isCollection;
+	      isCollection = collection.isCollection,
+
+	      atan2Big = util.bignumber.arctan2;
 
 	  /**
 	   * Calculate the inverse tangent function with two arguments, y/x.
@@ -18064,47 +21408,62 @@
 	      if (isNumber(x)) {
 	        return Math.atan2(y, x);
 	      }
+
+	      if (x instanceof BigNumber) {
+	        return atan2Big(new BigNumber(y), x, BigNumber);
+	      }
 	    }
 
-	    // TODO: support for complex computation of atan2
-
 	    if (isCollection(y) || isCollection(x)) {
 	      return collection.deepMap2(y, x, atan2);
 	    }
 
 	    if (isBoolean(y) || y === null) {
-	      return atan2(+y, x);
+	      return atan2(y ? 1 : 0, x);
 	    }
 	    if (isBoolean(x) || x === null) {
-	      return atan2(y, +x);
+	      return atan2(y, x ? 1 : 0);
 	    }
 
-	    // TODO: implement bignumber support
 	    if (y instanceof BigNumber) {
+	      if (isNumber(x)) {
+	        return atan2Big(y, new BigNumber(x), BigNumber);
+	      }
+
+	      if (x instanceof BigNumber) {
+	        return atan2Big(y, x, BigNumber);
+	      }
+
 	      return atan2(y.toNumber(), x);
 	    }
 	    if (x instanceof BigNumber) {
+	      if (y instanceof BigNumber) {
+	        return atan2Big(y, x, BigNumber);
+	      }
+
 	      return atan2(y, x.toNumber());
 	    }
 
+	    // TODO: support for complex computation of atan2
+
 	    throw new math.error.UnsupportedTypeError('atan2', math['typeof'](y), math['typeof'](x));
 	  };
 	};
 
 
 /***/ },
-/* 141 */
+/* 144 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
 	      Unit = __webpack_require__(11),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -18175,7 +21534,8 @@
 	    }
 
 	    if (isCollection(x)) {
-	      return collection.deepMap(x, atanh);
+	      // deep map collection, skip zeros since atanh(0) = 0
+	      return collection.deepMap(x, atanh, true);
 	    }
 
 	    if (isBoolean(x) || x === null) {
@@ -18192,18 +21552,18 @@
 
 
 /***/ },
-/* 142 */
+/* 145 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math, config) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
 	      Unit = __webpack_require__(11),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -18281,18 +21641,18 @@
 
 
 /***/ },
-/* 143 */
+/* 146 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
 	      Unit = __webpack_require__(11),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -18363,18 +21723,18 @@
 
 
 /***/ },
-/* 144 */
+/* 147 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math, config) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
 	      Unit = __webpack_require__(11),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -18449,18 +21809,18 @@
 
 
 /***/ },
-/* 145 */
+/* 148 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
 	      Unit = __webpack_require__(11),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -18539,18 +21899,18 @@
 
 
 /***/ },
-/* 146 */
+/* 149 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math, config) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
 	      Unit = __webpack_require__(11),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -18626,20 +21986,20 @@
 
 
 /***/ },
-/* 147 */
+/* 150 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
 	      Unit = __webpack_require__(11),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 	      number = util.number,
-
+	      
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
 	      isComplex = Complex.isComplex,
@@ -18717,18 +22077,18 @@
 
 
 /***/ },
-/* 148 */
+/* 151 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math, config) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
 	      Unit = __webpack_require__(11),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -18804,18 +22164,18 @@
 
 
 /***/ },
-/* 149 */
+/* 152 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
 	      Unit = __webpack_require__(11),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -18891,18 +22251,18 @@
 
 
 /***/ },
-/* 150 */
+/* 153 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math, config) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
 	      Unit = __webpack_require__(11),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -18962,7 +22322,8 @@
 	    }
 
 	    if (isCollection(x)) {
-	      return collection.deepMap(x, sin);
+	      // deep map collection, skip zeros since sin(0) = 0
+	      return collection.deepMap(x, sin, true);
 	    }
 
 	    if (isBoolean(x) || x === null) {
@@ -18979,18 +22340,18 @@
 
 
 /***/ },
-/* 151 */
+/* 154 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
 	      Unit = __webpack_require__(11),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -19050,7 +22411,8 @@
 	    }
 
 	    if (isCollection(x)) {
-	      return collection.deepMap(x, sinh);
+	      // deep map collection, skip zeros since sinh(0) = 0
+	      return collection.deepMap(x, sinh, true);
 	    }
 
 	    if (isBoolean(x) || x === null) {
@@ -19067,18 +22429,18 @@
 
 
 /***/ },
-/* 152 */
+/* 155 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math, config) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
 	      Unit = __webpack_require__(11),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -19139,7 +22501,8 @@
 	    }
 
 	    if (isCollection(x)) {
-	      return collection.deepMap(x, tan);
+	      // deep map collection, skip zeros since tan(0) = 0
+	      return collection.deepMap(x, tan, true);
 	    }
 
 	    if (isBoolean(x) || x === null) {
@@ -19156,18 +22519,18 @@
 
 
 /***/ },
-/* 153 */
+/* 156 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      BigNumber = math.type.BigNumber,
 	      Complex = __webpack_require__(7),
 	      Unit = __webpack_require__(11),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isNumber = util.number.isNumber,
 	      isBoolean = util['boolean'].isBoolean,
@@ -19230,7 +22593,8 @@
 	    }
 
 	    if (isCollection(x)) {
-	      return collection.deepMap(x, tanh);
+	      // deep map collection, skip zeros since tanh(0) = 0
+	      return collection.deepMap(x, tanh, true);
 	    }
 
 	    if (isBoolean(x) || x === null) {
@@ -19247,16 +22611,16 @@
 
 
 /***/ },
-/* 154 */
+/* 157 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      Unit = __webpack_require__(11),
-	      collection = __webpack_require__(14),
+	      collection = math.collection,
 
 	      isString = util.string.isString,
 	      isUnit = Unit.isUnit,
@@ -19309,13 +22673,13 @@
 
 
 /***/ },
-/* 155 */
+/* 158 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 	      object = util.object;
 
 	  /**
@@ -19347,13 +22711,13 @@
 
 
 /***/ },
-/* 156 */
+/* 159 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var Matrix = __webpack_require__(10);
+	  var Matrix = math.type.Matrix;
 
 	  /**
 	   * Sort the items in a matrix.
@@ -19392,7 +22756,7 @@
 	      if (size.length > 1) {
 	        throw new Error('Only one dimensional matrices supported');
 	      }
-	      return new Matrix(_filter(x.toArray(), test));
+	      return math.matrix(_filter(x.toArray(), test));
 	    }
 	    else if (Array.isArray(x)) {
 	      return _filter(x, test);
@@ -19427,13 +22791,13 @@
 	};
 
 /***/ },
-/* 157 */
+/* 160 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 	      string = util.string;
 
 	  /**
@@ -19512,13 +22876,13 @@
 
 
 /***/ },
-/* 158 */
+/* 161 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      Complex = __webpack_require__(7),
 	      Unit = __webpack_require__(11),
@@ -19591,7 +22955,7 @@
 	      // istanbul ignore else (we cannot unit test the else case in a node.js environment)
 	      if (true) {
 	        // load the file using require
-	        var _module = __webpack_require__(202)(object);
+	        var _module = __webpack_require__(206)(object);
 	        math_import(_module, options);
 	      }
 	      else {
@@ -19672,17 +23036,17 @@
 
 
 /***/ },
-/* 159 */
+/* 162 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var Matrix = __webpack_require__(10);
+	  var Matrix = math.type.Matrix;
 
 
 	  /**
-	   * Create a new matrix or array with the results of the callback function executed on
+	   * Create a math.matrix or array with the results of the callback function executed on
 	   * each entry of the matrix/array.
 	   *
 	   * Syntax:
@@ -19738,13 +23102,13 @@
 
 
 /***/ },
-/* 160 */
+/* 163 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var util = __webpack_require__(171),
+	  var util = __webpack_require__(174),
 
 	      isString = util.string.isString;
 
@@ -19822,13 +23186,13 @@
 
 
 /***/ },
-/* 161 */
+/* 164 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var Matrix = __webpack_require__(10);
+	  var Matrix = math.type.Matrix;
 
 	  /**
 	   * Sort the items in a matrix.
@@ -19890,7 +23254,7 @@
 	      if (size.length > 1) {
 	        throw new Error('Only one dimensional matrices supported');
 	      }
-	      return new Matrix(x.toArray().sort(_compare));
+	      return math.matrix(x.toArray().sort(_compare));
 	    }
 	    else if (Array.isArray(x)) {
 	      return x.sort(_compare);
@@ -19902,16 +23266,16 @@
 	};
 
 /***/ },
-/* 162 */
+/* 165 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var types = __webpack_require__(334),
+	  var types = __webpack_require__(337),
 
 	      Complex = __webpack_require__(7),
-	      Matrix = __webpack_require__(10),
+	      Matrix = math.type.Matrix,
 	      Unit = __webpack_require__(11),
 	      Index = __webpack_require__(9),
 	      Range = __webpack_require__(8),
@@ -19984,13 +23348,13 @@
 
 
 /***/ },
-/* 163 */
+/* 166 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	module.exports = function (math) {
-	  var Matrix = __webpack_require__(10);
+	  var Matrix = math.type.Matrix;
 
 	  /**
 	   * Iterate over all elements of a matrix/array, and executes the given callback function.
@@ -20046,7 +23410,7 @@
 	};
 
 /***/ },
-/* 164 */
+/* 167 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
@@ -20054,7 +23418,7 @@
 	var BigNumber = __webpack_require__(5);
 	var isNumber = __webpack_require__(3).isNumber;
 	var digits = __webpack_require__(3).digits;
-	var memoize = __webpack_require__(335).memoize;
+	var memoize = __webpack_require__(338).memoize;
 
 	/**
 	 * Test whether value is a BigNumber
@@ -20066,7 +23430,7 @@
 	};
 
 
-	/*************************************
+	/************************************* 
 	 *             Constants             *
 	 *************************************/
 
@@ -20593,7 +23957,7 @@
 	    }
 
 	    Big.config({precision: precision + 2});
-	    x = Big.ONE.div(x);
+	    x = Big.ONE.div(x); 
 	    Big.config({precision: precision});
 
 	    absX = x.abs();
@@ -20656,6 +24020,7 @@
 	  var precision = Big.precision;
 	  if ((!reciprocal && !x.isFinite()) || (reciprocal && x.isZero())) {
 	    var halfPi = exports.pi(precision + 2).div(2).toDP(precision - 1);
+	    halfPi.constructor = Big;
 	    halfPi.s = x.s;
 
 	    return halfPi;
@@ -20694,6 +24059,41 @@
 	};
 
 	/**
+	 * Calculate the arctangent of y, x
+	 *
+	 * @param {BigNumber} y
+	 * @param {BigNumber} x
+	 * @param {DecimalFactory} Big   current BigNumber constructor
+	 * @returns {BigNumber} arctangent of y, x
+	 */
+	exports.arctan2 = function (y, x, Big) {
+	  var precision = Big.precision;
+	  if (x.isZero()) {
+	    if (y.isZero()) {
+	      return new Big(NaN);
+	    }
+
+	    var halfPi = exports.pi(precision + 2).div(2).toDP(precision - 1);
+	    halfPi.constructor = Big;
+	    halfPi.s = y.s;
+
+	    return halfPi;
+	  }
+
+	  Big.config({precision: precision + 2});
+
+	  var ret = exports.arctan_arccot(y.div(x), Big, false);
+	  if (x.isNegative()) {
+	    var pi = exports.pi(precision + 2);
+	    ret = y.isNegative() ? ret.minus(pi) : ret.plus(pi);
+	  }
+
+	  ret.constructor = Big;
+	  Big.config({precision: precision});
+	  return ret.toDP(precision - 1);
+	};
+
+	/**
 	 * Calculate the hyperbolic arccosine, arcsine, arcsecant, or arccosecant of x
 	 *
 	 * acosh(x) = ln(x + sqrt(x^2 - 1))
@@ -20916,7 +24316,7 @@
 	    return new Big(Infinity);
 	  }
 
-	  Big.config({precision: precision + 2});
+	  Big.config({precision: precision + 4});
 	  var sin = exports.cos_sin_sec_csc(y, Big, 1, false);
 	  var cos = sinToCos(sin);
 
@@ -21093,7 +24493,7 @@
 	  var constNum = new Big(one);
 	  var constDen = new Big(one);
 
-	  var bigK = new Big(one);
+	  var bigK = new Big(one); 
 	  for (var k = 3; !y.equals(yPrev); k += 2) {
 	    polyNum = polyNum.times(x2);
 
@@ -21422,29 +24822,20 @@
 	  // undefined default precision instead of 0.
 	};
 
-	/* Helper functions */
-	function BigNumberCopy(x) {
-	  var Big = BigNumber.constructor({precision: x.constructor.precision});
-	  var y = new Big(x);
-	  y.constructor = Big;      // Not sure why I have to do this...
-
-	  return y;
-	}
-
 
 /***/ },
-/* 165 */
+/* 168 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	var number = __webpack_require__(3),
-	    string = __webpack_require__(205),
+	    string = __webpack_require__(175),
 	    object = __webpack_require__(2),
-	    types = __webpack_require__(334),
+	    types = __webpack_require__(337),
 
-	    DimensionError = __webpack_require__(168),
-	    IndexError = __webpack_require__(169),
+	    DimensionError = __webpack_require__(171),
+	    IndexError = __webpack_require__(172),
 
 	    isArray = Array.isArray;
 
@@ -21815,16 +25206,16 @@
 	exports.isArray = isArray;
 
 /***/ },
-/* 166 */
+/* 169 */
 /***/ function(module, exports, __webpack_require__) {
 
-	module.exports = '1.4.0';
+	module.exports = '1.5.0';
 	// Note: This file is automatically generated when building math.js.
 	// Changes made in this file will be overwritten.
 
 
 /***/ },
-/* 167 */
+/* 170 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
@@ -21863,7 +25254,7 @@
 
 
 /***/ },
-/* 168 */
+/* 171 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
@@ -21903,7 +25294,7 @@
 
 
 /***/ },
-/* 169 */
+/* 172 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
@@ -21954,7 +25345,7 @@
 
 
 /***/ },
-/* 170 */
+/* 173 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
@@ -21997,31 +25388,143 @@
 
 
 /***/ },
-/* 171 */
+/* 174 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
-	exports.array = __webpack_require__(165);
-	exports['boolean'] = __webpack_require__(204);
+	exports.array = __webpack_require__(168);
+	exports['boolean'] = __webpack_require__(208);
 	exports.number = __webpack_require__(3);
-	exports.bignumber = __webpack_require__(164);
+	exports.bignumber = __webpack_require__(167);
 	exports.object = __webpack_require__(2);
-	exports.string = __webpack_require__(205);
-	exports.types = __webpack_require__(334);
-
-
-/***/ },
-/* 172 */
-/***/ function(module, exports, __webpack_require__) {
-
-	'use strict';
-
-	var Node = __webpack_require__(180),
-	    object = __webpack_require__(2),
-	    string = __webpack_require__(205),
-	    collection = __webpack_require__(14),
-	    util = __webpack_require__(171),
+	exports.string = __webpack_require__(175);
+	exports.types = __webpack_require__(337);
+
+
+/***/ },
+/* 175 */
+/***/ function(module, exports, __webpack_require__) {
+
+	'use strict';
+
+	var number = __webpack_require__(3);
+	var bignumber = __webpack_require__(167);
+	var BigNumber = __webpack_require__(5);
+
+	/**
+	 * Test whether value is a String
+	 * @param {*} value
+	 * @return {Boolean} isString
+	 */
+	exports.isString = function(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(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.
+	 *
+	 * Usage:
+	 *     math.format(value)
+	 *     math.format(value, precision)
+	 *
+	 * If value is a function, the returned string is 'function' unless the function
+	 * has a property `description`, in that case this properties value is returned.
+	 *
+	 * Example usage:
+	 *     math.format(2/7);                // '0.2857142857142857'
+	 *     math.format(math.pi, 3);         // '3.14'
+	 *     math.format(new Complex(2, 3));  // '2 + 3i'
+	 *     math.format('hello');            // '"hello"'
+	 *
+	 * @param {*} value             Value to be stringified
+	 * @param {Object | Number | Function} [options]  Formatting options. See
+	 *                                                lib/util/number:format for a
+	 *                                                description of the available
+	 *                                                options.
+	 * @return {String} str
+	 */
+	exports.format = function(value, options) {
+	  if (number.isNumber(value)) {
+	    return number.format(value, options);
+	  }
+
+	  if (value instanceof BigNumber) {
+	    return bignumber.format(value, options);
+	  }
+
+	  if (Array.isArray(value)) {
+	    return formatArray(value, options);
+	  }
+
+	  if (exports.isString(value)) {
+	    return '"' + value + '"';
+	  }
+
+	  if (typeof value === 'function') {
+	    return value.syntax ? value.syntax + '' : 'function';
+	  }
+
+	  if (value instanceof Object) {
+	    if (typeof value.format === 'function') {
+	      return value.format(options);
+	    }
+	    else {
+	      return value.toString();
+	    }
+	  }
+
+	  return String(value);
+	};
+
+	/**
+	 * Recursively format an n-dimensional matrix
+	 * Example output: "[[1, 2], [3, 4]]"
+	 * @param {Array} array
+	 * @param {Object | Number | Function} [options]  Formatting options. See
+	 *                                                lib/util/number:format for a
+	 *                                                description of the available
+	 *                                                options.
+	 * @returns {String} str
+	 */
+	function formatArray (array, options) {
+	  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], options);
+	    }
+	    str += ']';
+	    return str;
+	  }
+	  else {
+	    return exports.format(array, options);
+	  }
+	}
+
+
+/***/ },
+/* 176 */
+/***/ function(module, exports, __webpack_require__) {
+
+	'use strict';
+
+	var Node = __webpack_require__(184),
+	    string = __webpack_require__(175),
 
 	    isArray = Array.isArray,
 	    isNode = Node.isNode;
@@ -22041,7 +25544,7 @@
 
 	  // validate input
 	  if (!isArray(this.nodes) || !this.nodes.every(isNode)) {
-	    throw new TypeError('Array containing Nodes expected')
+	    throw new TypeError('Array containing Nodes expected');
 	  }
 	}
 
@@ -22098,7 +25601,7 @@
 	 * @return {ArrayNode}
 	 */
 	ArrayNode.prototype.clone = function() {
-	  return new ArrayNode(this.nodes.slice(0))
+	  return new ArrayNode(this.nodes.slice(0));
 	};
 
 	/**
@@ -22112,26 +25615,28 @@
 
 	/**
 	 * Get LaTeX representation
+	 * @param {Object|function} callback(s)
+	 * @param {String} type
 	 * @return {String} str
 	 */
-	ArrayNode.prototype.toTex = function(type) {
-	  type = type || 'bmatrix';
-	  var s = '\\begin{' + type + '}';
+	ArrayNode.prototype._toTex = function(callbacks) {
+	  this.latexType = this.latexType || 'bmatrix';
+	  var s = '\\begin{' + this.latexType + '}';
 
 	  this.nodes.forEach(function(node) {
 	    if (node.nodes) {
 	      s += node.nodes.map(function(childNode) {
-	        return childNode.toTex();
+	        return childNode.toTex(callbacks);
 	      }).join('&');
 	    }
 	    else {
-	      s += node.toTex();
+	      s += node.toTex(callbacks);
 	    }
 
 	    // new line
 	    s += '\\\\';
 	  });
-	  s += '\\end{' + type + '}';
+	  s += '\\end{' + this.latexType + '}';
 	  return s;
 	};
 
@@ -22139,18 +25644,19 @@
 
 
 /***/ },
-/* 173 */
+/* 177 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
-	var Node = __webpack_require__(180),
-	    ArrayNode = __webpack_require__(172),
-
-	    keywords = __webpack_require__(337),
-
-	    latex = __webpack_require__(338),
-	    isString = __webpack_require__(205).isString;
+	var Node = __webpack_require__(184),
+	    ArrayNode = __webpack_require__(176),
+
+	    keywords = __webpack_require__(340),
+	    operators = __webpack_require__(341),
+
+	    latex = __webpack_require__(342),
+	    isString = __webpack_require__(175).isString;
 
 	/**
 	 * @constructor AssignmentNode
@@ -22221,33 +25727,53 @@
 	 * @return {String}
 	 */
 	AssignmentNode.prototype.toString = function() {
-	  return this.name + ' = ' + this.expr.toString();
+	  var precedence = operators.getPrecedence(this);
+	  var exprPrecedence = operators.getPrecedence(this.expr);
+	  var expr = this.expr.toString();
+	  if ((exprPrecedence !== null) && (exprPrecedence <= precedence)) {
+	    expr = '(' + expr + ')';
+	  }
+	  return this.name + ' = ' + expr;
 	};
 
 	/**
 	 * Get LaTeX representation
+	 * @param {Object|function} callback(s)
 	 * @return {String}
 	 */
-	AssignmentNode.prototype.toTex = function() {
+	AssignmentNode.prototype._toTex = function(callbacks) {
+	  var precedence = operators.getPrecedence(this);
+	  var exprPrecedence = operators.getPrecedence(this.expr);
+
+	  var expr = this.expr.toTex(callbacks);
+	  if ((exprPrecedence !== null) && (exprPrecedence <= precedence)) {
+	    //adds visible round brackets
+	    expr = latex.addBraces(expr, true);
+	  }
+	  else {
+	    //adds (invisible) curly braces
+	    expr = latex.addBraces(expr, false);
+	  }
+
 	  var brace;
 	  if (this.expr instanceof ArrayNode) {
 	    brace = ['\\mathbf{', '}'];
 	  }
-	  return latex.addBraces(latex.toSymbol(this.name), brace) + '=' +
-	      latex.addBraces(this.expr.toTex());
+	  return latex.addBraces(latex.toSymbol(this.name), brace) + '=' + expr;
 	};
 
 	module.exports = AssignmentNode;
 
+
 /***/ },
-/* 174 */
+/* 178 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
-	var Node = __webpack_require__(180);
+	var Node = __webpack_require__(184);
 	var ResultSet = __webpack_require__(13);
-	var isBoolean = __webpack_require__(204).isBoolean;
+	var isBoolean = __webpack_require__(208).isBoolean;
 
 	/**
 	 * @constructor BlockNode
@@ -22367,11 +25893,12 @@
 
 	/**
 	 * Get LaTeX representation
+	 * @param {Object|function} callback(s)
 	 * @return {String} str
 	 */
-	BlockNode.prototype.toTex = function() {
+	BlockNode.prototype._toTex = function(callbacks) {
 	  return this.blocks.map(function (param) {
-	    return param.node.toTex() + (param.visible ? '' : ';');
+	    return param.node.toTex(callbacks) + (param.visible ? '' : ';');
 	  }).join('\n');
 	};
 
@@ -22379,17 +25906,18 @@
 
 
 /***/ },
-/* 175 */
+/* 179 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
-	var Node = __webpack_require__(180);
-	var latex = __webpack_require__(338);
+	var Node = __webpack_require__(184);
+	var latex = __webpack_require__(342);
 	var BigNumber = __webpack_require__(5);
 	var Complex = __webpack_require__(7);
 	var Unit = __webpack_require__(11);
-	var util = __webpack_require__(171);
+	var util = __webpack_require__(174);
+	var operators = __webpack_require__(341);
 	var isString = util.string.isString;
 	var isNumber = util.number.isNumber;
 	var isBoolean = util['boolean'].isBoolean;
@@ -22503,23 +26031,47 @@
 	 * @return {String} str
 	 */
 	ConditionalNode.prototype.toString = function() {
-	  // TODO: not nice adding parenthesis al the time
-	  return '(' + this.condition.toString() + ') ? (' +
-	      this.trueExpr.toString() + ') : (' +
-	      this.falseExpr.toString() + ')';
+	  var precedence = operators.getPrecedence(this);
+
+	  //Enclose Arguments in parentheses if they are an OperatorNode
+	  //or have lower or equal precedence
+	  //NOTE: enclosing all OperatorNodes in parentheses is a decision
+	  //purely based on aesthetics and readability
+	  var condition = this.condition.toString();
+	  var conditionPrecedence = operators.getPrecedence(this.condition);
+	  if ((this.condition.type === 'OperatorNode')
+	      || ((conditionPrecedence !== null) && (conditionPrecedence <= precedence))) {
+	    condition = '(' + condition + ')';
+	  }
+
+	  var trueExpr = this.trueExpr.toString();
+	  var truePrecedence = operators.getPrecedence(this.trueExpr);
+	  if ((this.trueExpr.type === 'OperatorNode')
+	      || ((truePrecedence !== null) && (truePrecedence <= precedence))) {
+	    trueExpr = '(' + trueExpr + ')';
+	  }
+
+	  var falseExpr = this.falseExpr.toString();
+	  var falsePrecedence = operators.getPrecedence(this.falseExpr);
+	  if ((this.falseExpr.type === 'OperatorNode')
+	      || ((falsePrecedence !== null) && (falsePrecedence <= precedence))) {
+	    falseExpr = '(' + falseExpr + ')';
+	  }
+	  return condition + ' ? ' + trueExpr + ' : ' + falseExpr;
 	};
 
 	/**
 	 * Get LaTeX representation
+	 * @param {Object|function} callback(s)
 	 * @return {String} str
 	 */
-	ConditionalNode.prototype.toTex = function() {
+	ConditionalNode.prototype._toTex = function(callbacks) {
 	  var s = (
-	      latex.addBraces(this.trueExpr.toTex()) +
+	      latex.addBraces(this.trueExpr.toTex(callbacks)) +
 	      ', &\\quad' +
-	      latex.addBraces('\\text{if}\\;' + this.condition.toTex())
+	      latex.addBraces('\\text{if}\\;' + this.condition.toTex(callbacks))
 	      ) + '\\\\' + (
-	      latex.addBraces(this.falseExpr.toTex()) +
+	      latex.addBraces(this.falseExpr.toTex(callbacks)) +
 	      ', &\\quad' +
 	      latex.addBraces('\\text{otherwise}')
 	      );
@@ -22534,15 +26086,15 @@
 
 
 /***/ },
-/* 176 */
+/* 180 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
-	var Node = __webpack_require__(180);
+	var Node = __webpack_require__(184);
 	var BigNumber = __webpack_require__(5);
-	var type = __webpack_require__(334).type;
-	var isString = __webpack_require__(205).isString;
+	var type = __webpack_require__(337).type;
+	var isString = __webpack_require__(175).isString;
 
 	/**
 	 * A ConstantNode holds a constant value like a number or string. A ConstantNode
@@ -22695,9 +26247,10 @@
 
 	/**
 	 * Get LaTeX representation
+	 * @param {Object|function} callback(s)
 	 * @return {String} str
 	 */
-	ConstantNode.prototype.toTex = function() {
+	ConstantNode.prototype._toTex = function(callbacks) {
 	  var value = this.value,
 	      index;
 	  switch (this.valueType) {
@@ -22721,14 +26274,14 @@
 
 
 /***/ },
-/* 177 */
+/* 181 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
-	var Node = __webpack_require__(180);
-	var RangeNode = __webpack_require__(182);
-	var SymbolNode = __webpack_require__(183);
+	var Node = __webpack_require__(184);
+	var RangeNode = __webpack_require__(186);
+	var SymbolNode = __webpack_require__(187);
 
 	var BigNumber = __webpack_require__(5);
 	var Range = __webpack_require__(8);
@@ -22935,24 +26488,27 @@
 
 	/**
 	 * Get LaTeX representation
+	 * @param {Object|function} callback(s)
 	 * @return {String} str
 	 */
-	IndexNode.prototype.toTex = function() {
-	  return this.object.toTex() + '[' + this.ranges.join(', ') + ']';
+	IndexNode.prototype._toTex = function(callbacks) {
+	  return this.object.toTex(callbacks) + '[' + this.ranges.join(', ') + ']';
 	};
 
 	module.exports = IndexNode;
 
+
 /***/ },
-/* 178 */
+/* 182 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
-	var Node = __webpack_require__(180);
-	var keywords = __webpack_require__(337);
-	var latex = __webpack_require__(338);
-	var isString = __webpack_require__(205).isString;
+	var Node = __webpack_require__(184);
+	var keywords = __webpack_require__(340);
+	var latex = __webpack_require__(342);
+	var operators = __webpack_require__(341);
+	var isString = __webpack_require__(175).isString;
 	var isArray = Array.isArray;
 
 	/**
@@ -23045,34 +26601,54 @@
 	 * @return {String} str
 	 */
 	FunctionAssignmentNode.prototype.toString = function() {
+	  var precedence = operators.getPrecedence(this);
+	  var exprPrecedence = operators.getPrecedence(this.expr);
+
+	  var expr = this.expr.toString();
+	  if ((exprPrecedence !== null) && (exprPrecedence <= precedence)) {
+	    expr = '(' + expr + ')';
+	  }
 	  return 'function ' + this.name +
-	      '(' + this.params.join(', ') + ') = ' +
-	      this.expr.toString();
+	      '(' + this.params.join(', ') + ') = ' + expr;
 	};
 
 	/**
 	 * get LaTeX representation
+	 * @param {Object|function} callback(s)
 	 * @return {String} str
 	 */
-	FunctionAssignmentNode.prototype.toTex = function() {
-	  return this.name +
-	      latex.addBraces(this.params.map(latex.toSymbol).join(', '), true) + '=' +
-	      latex.addBraces(this.expr.toTex());
+	FunctionAssignmentNode.prototype._toTex = function(callbacks) {
+	  var precedence = operators.getPrecedence(this);
+	  var exprPrecedence = operators.getPrecedence(this.expr);
+
+	  var expr = this.expr.toTex(callbacks);
+	  if ((exprPrecedence !== null) && (exprPrecedence <= precedence)) {
+	    //adds visible round brackets
+	    expr = latex.addBraces(expr, true);
+	  }
+	  else {
+	    //add (invisible) curly braces
+	    expr = latex.addBraces(expr, false);
+	  }
+
+	  return latex.toFunction(this.name)
+	       + latex.addBraces(this.params.map(latex.toSymbol).join(', '), true) + '=' //FIXME, this doesn't call toTex on the parameters AFAIK (toSymbol)
+	       + expr;
 	};
 
 	module.exports = FunctionAssignmentNode;
 
 
 /***/ },
-/* 179 */
+/* 183 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
-	var Node = __webpack_require__(180);
-	var SymbolNode = __webpack_require__(183);
+	var Node = __webpack_require__(184);
+	var SymbolNode = __webpack_require__(187);
 
-	var latex = __webpack_require__(338);
+	var latex = __webpack_require__(342);
 	var isNode = Node.isNode;
 	var isArray = Array.isArray;
 
@@ -23182,22 +26758,31 @@
 
 	/**
 	 * Get LaTeX representation
+	 * @param {Object|function} callback(s)
 	 * @return {String} str
 	 */
-	FunctionNode.prototype.toTex = function() {
-	  return latex.toArgs(this);
+	FunctionNode.prototype._toTex = function(callbacks) {
+	  return latex.toArgs(this, callbacks);
+	};
+
+	/**
+	 * Get identifier.
+	 * @return {String}
+	 */
+	FunctionNode.prototype.getIdentifier = function () {
+	  return this.type + ':' + this.name;
 	};
 
 	module.exports = FunctionNode;
 
 
 /***/ },
-/* 180 */
+/* 184 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
-	var keywords = __webpack_require__(337);
+	var keywords = __webpack_require__(340);
 
 	/**
 	 * Node
@@ -23418,11 +27003,70 @@
 	};
 
 	/**
-	 * Get LaTeX representation
-	 * @return {String}
-	 */
-	Node.prototype.toTex = function() {
-	  return '';
+	 * Get LaTeX representation. (wrapper function)
+	 * This functions get's either an object containing callbacks or
+	 * a single callback. It decides whether to call the callback and if
+	 * not or if the callback returns nothing, it calls the default
+	 * LaTeX implementation of the node (_toTex).
+	 *
+	 * @param {Object|function} callback(s)
+	 * @return {String}
+	 */
+	Node.prototype.toTex = function(callback) {
+	  var customTex;
+	  if (this.type === 'ArrayNode') {
+	    //FIXME this is only a workaround for a breaking change,
+	    //remove this in version2
+	    delete this.latexType;
+	  }
+	  if (typeof callback === 'object') {
+	    if ((this.type === 'FunctionNode') && callback.hasOwnProperty(this.name)) {
+	      //if callback is a map of callback functions and this is a FunctionNode
+	      customTex = callback[this.name](this, callback);
+	    }
+	  }
+	  else if (typeof callback === 'function') {
+	    //if callback is a function
+	    customTex = callback(this, callback);
+	  }
+	  else if ((typeof callback === 'string') && (this.type === 'ArrayNode')) {
+	    //FIXME this is only a workaround for a breaking change,
+	    //remove this in version2
+	    this.latexType = callback;
+	  }
+	  else if (typeof callback !== 'undefined') {
+	    throw new TypeError('Object or function expected as callback');
+	  }
+
+	  if (typeof customTex !== 'undefined') {
+	    return customTex;
+	  }
+
+	  return this._toTex(callback);
+	};
+
+	/**
+	 * Internal function to generate the LaTeX output.
+	 * This has to be implemented by every Node
+	 *
+	 * @param {Object}|function}
+	 * @throws {Error}
+	 */
+	Node.prototype._toTex = function () {
+	  if (this.type === 'Node') {
+	    //FIXME remove this in v2
+	    return '';
+	  }
+	  //must be implemented by each of the Node implementations
+	  throw new Error('_toTex not implemented for this Node');
+	};
+
+	/**
+	 * Get identifier.
+	 * @return {String}
+	 */
+	Node.prototype.getIdentifier = function () {
+	 return this.type;
 	};
 
 	/**
@@ -23474,16 +27118,19 @@
 
 
 /***/ },
-/* 181 */
+/* 185 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
-	var Node = __webpack_require__(180),
-	    ConstantNode = __webpack_require__(176),
-	    SymbolNode = __webpack_require__(183),
-	    FunctionNode = __webpack_require__(179),
-	    latex = __webpack_require__(338);
+	var Node = __webpack_require__(184),
+	    ConstantNode = __webpack_require__(180),
+	    SymbolNode = __webpack_require__(187),
+	    FunctionNode = __webpack_require__(183),
+	    latex = __webpack_require__(342),
+	    operators = __webpack_require__(341),
+	    isArray = Array.isArray,
+	    isNode = Node.isNode;
 
 	/**
 	 * @constructor OperatorNode
@@ -23499,7 +27146,17 @@
 	    throw new SyntaxError('Constructor must be called with the new operator');
 	  }
 
-	  // TODO: validate input
+	  //validate input
+	  if (typeof op !== 'string') {
+	    throw new TypeError('string expected for parameter "op"');
+	  }
+	  if (typeof fn !== 'string') {
+	    throw new TypeError('string expected for parameter "fn"');
+	  }
+	  if (!isArray(args) || !args.every(isNode)) {
+	    throw new TypeError('Array containing Nodes expected for parameter "args"');
+	  }
+
 	  this.op = op;
 	  this.fn = fn;
 	  this.args = args || [];
@@ -23561,148 +27218,219 @@
 	};
 
 	/**
-	 * Get string representation
+	 * Calculate which parentheses are necessary. Gets an OperatorNode
+	 * (which is the root of the tree) and an Array of Nodes
+	 * (this.args) and returns an array where 'true' means that an argument
+	 * has to be enclosed in parentheses whereas 'false' means the opposite.
+	 *
+	 * @param {OperatorNode} root
+	 * @param {Node[]} arguments
+	 * @return {bool[]}
+	 * @private
+	 */
+	function calculateNecessaryParentheses (root, args) {
+	  //precedence of the root OperatorNode
+	  var precedence = operators.getPrecedence(root);
+	  var associativity = operators.getAssociativity(root);
+
+	  switch (args.length) {
+	    case 1: //unary operators
+	      //precedence of the operand
+	      var operandPrecedence = operators.getPrecedence(args[0]);
+
+	      if (operandPrecedence === null) {
+	        //if the operand has no defined precedence, no parens are needed
+	        return [false];
+	      }
+
+	      if (operandPrecedence <= precedence) {
+	        //if the operands precedence is lower, parens are needed
+	        return [true];
+	      }
+
+	      //otherwise, no parens needed
+	      return [false];
+
+	    case 2: //binary operators
+	      var lhsParens; //left hand side needs parenthesis?
+	      //precedence of the left hand side
+	      var lhsPrecedence = operators.getPrecedence(args[0]);
+	      //is the root node associative with the left hand side
+	      var assocWithLhs = operators.isAssociativeWith(root, args[0]);
+
+	      if (lhsPrecedence === null) {
+	        //if the left hand side has no defined precedence, no parens are needed
+	        //FunctionNode for example
+	        lhsParens = false;
+	      }
+	      else if ((lhsPrecedence === precedence) && (associativity === 'right') && !assocWithLhs) {
+	        //In case of equal precedence, if the root node is left associative
+	        // parens are **never** necessary for the left hand side.
+	        //If it is right associative however, parens are necessary
+	        //if the root node isn't associative with the left hand side
+	        lhsParens = true;
+	      }
+	      else if (lhsPrecedence < precedence) {
+	        lhsParens = true;
+	      }
+	      else {
+	        lhsParens = false;
+	      }
+
+	      var rhsParens; //right hand side needs parenthesis?
+	      //precedence of the right hand side
+	      var rhsPrecedence = operators.getPrecedence(args[1]);
+	      //is the root node associative with the right hand side?
+	      var assocWithRhs = operators.isAssociativeWith(root, args[1]);
+
+	      if (rhsPrecedence === null) {
+	        //if the right hand side has no defined precedence, no parens are needed
+	        //FunctionNode for example
+	        rhsParens = false;
+	      }
+	      else if ((rhsPrecedence === precedence) && (associativity === 'left') && !assocWithRhs) {
+	        //In case of equal precedence, if the root node is right associative
+	        // parens are **never** necessary for the right hand side.
+	        //If it is left associative however, parens are necessary
+	        //if the root node isn't associative with the right hand side
+	        rhsParens = true;
+	      }
+	      else if (rhsPrecedence < precedence) {
+	        rhsParens = true;
+	      }
+	      else {
+	        rhsParens = false;
+	      }
+	      return [lhsParens, rhsParens];
+	    default:
+	      //behavior is undefined, fall back to putting everything in parens
+	      var parens = [];
+	      args.forEach(function () {
+	        parens.push(true);
+	      });
+	      return parens;
+	  }
+	}
+
+	/**
+	 * Get string representation.
 	 * @return {String} str
 	 */
 	OperatorNode.prototype.toString = function() {
 	  var args = this.args;
+	  var parens = calculateNecessaryParentheses(this, args);
 
 	  switch (args.length) {
-	    case 1:
-	      if (this.op == '-') {
-	        // special case: unary minus
-	        return '-' + args[0].toString();
-	      }
-	      else {
-	        // for example '5!'
-	        return args[0].toString() + this.op;
-	      }
-
-	    case 2: // for example '2+3'
-	      var lhs = args[0].toString();
-	      if (args[0] instanceof OperatorNode) {
+	    case 1: //unary operators
+	      var assoc = operators.getAssociativity(this);
+
+	      var operand = args[0].toString();
+	      if (parens[0]) {
+	        operand = '(' + operand + ')';
+	      }
+
+	      if (assoc === 'right') { //prefix operator
+	        return this.op + operand;
+	      }
+	      else if (assoc === 'left') { //postfix
+	        return operand + this.op;
+	      }
+
+	      //fall back to postfix
+	      return operand + this.op;
+
+	    case 2:
+	      var lhs = args[0].toString(); //left hand side
+	      var rhs = args[1].toString(); //right hand side
+	      if (parens[0]) { //left hand side in parenthesis?
 	        lhs = '(' + lhs + ')';
 	      }
-	      var rhs = args[1].toString();
-	      if (args[1] instanceof OperatorNode) {
+	      if (parens[1]) { //right hand side in parenthesis?
 	        rhs = '(' + rhs + ')';
 	      }
+
 	      return lhs + ' ' + this.op + ' ' + rhs;
 
-	    default: // this should not occur. format as a function call
-	      return this.op + '(' + this.args.join(', ') + ')';
+	    default:
+	      //fallback to formatting as a function call
+	      return this.fn + '(' + this.args.join(', ') + ')';
 	  }
 	};
 
 	/**
 	 * Get LaTeX representation
+	 * @param {Object|function} callback(s)
 	 * @return {String} str
 	 */
-	OperatorNode.prototype.toTex = function() {
-	  var args = this.args,
-	      mop = latex.toOperator(this.op),
-	      lp = args[0],
-	      rp = args[1];
-
-	  switch (args.length) {
-	    case 1:
-	      var operand = lp.toTex();
-	      switch (this.op) {
-	        case '-': //unary minus needs brackets around '-' and '+'
-	          if (lp instanceof OperatorNode && (lp.op === '-' || lp.op === '+')) {
-	            return this.op + latex.addBraces(operand, true);
-	          }
-	        case '+':
-	          return this.op + operand;
-	          break;
-	        default: // fox example '5!'
-	          if (lp instanceof OperatorNode) {
-	            return latex.addBraces(operand, true) + this.op;
-	          }
-	          return operand + this.op;
-	      }
-
-	    case 2: // for example '2+3'
-	      var lhs = lp.toTex(),
-	          lhb = false,
-	          rhs = rp.toTex(),
-	          rhb = false,
-	          lop = '',
-	          rop = '';
-
-	      switch (this.op) {
-	        case '/':
-	          lop = mop;
-	          mop = '';
-
-	          break;
-
-	        case '*':
-	          if (lp instanceof OperatorNode) {
-	            if (lp.op === '+' || lp.op === '-') {
-	              lhb = true;
-	            }
-	          }
-
-	          if (rp instanceof OperatorNode) {
-	            if (rp.op === '+' || rp.op === '-' || rp.op === '*') {
-	              rhb = true;
-	            }
-	          }
-
-	          if ((lp instanceof ConstantNode || lp instanceof OperatorNode) &&
-	              (rp instanceof ConstantNode || rp instanceof OperatorNode)) {
-	            mop = ' \\cdot ';
-	          }
-	          else {
-	            mop = ' \\, ';
-	          }
-
-	          break;
-
-	        case '-':
-	          if (rp instanceof OperatorNode) {
-	            if (rp.op === '+' | rp.op === '-' ) {
-	              rhb = true;
-	            }
-	          }
-	          break;
-
-	        case '^':
-	          if (lp instanceof OperatorNode || lp instanceof FunctionNode) {
-	            lhb = true;
-	          }
-	          else if (lp instanceof SymbolNode) {
-	            lhb = null;
-	          }
-
-	          break;
-
-	        case 'to':
-	          rhs = latex.toUnit(rhs, true);
-	          break;
-	      }
-
-	      lhs = latex.addBraces(lhs, lhb);
-	      rhs = latex.addBraces(rhs, rhb);
-
-	      return lop + lhs + mop + rhs + rop;
-
-	    default: // this should not occur. format as a function call
-	      return mop + '(' + this.args.map(latex.toSymbol).join(', ') + ')';
-	  }
+	OperatorNode.prototype._toTex = function(callbacks) {
+	 var args = this.args; 
+	 var parens = calculateNecessaryParentheses(this, args);
+	 var op = latex.toOperator(this.op); //operator
+
+	 switch (args.length) {
+	   case 1: //unary operators
+	     var assoc = operators.getAssociativity(this);
+
+	     var operand = args[0].toTex(callbacks);
+	     if (parens[0]) {
+	       operand = latex.addBraces(operand, true);
+	     }
+
+	     if (assoc === 'right') { //prefix operator
+	       return op + operand;
+	     }
+	     else if (assoc === 'left') { //postfix operator
+	       return operand + op;
+	     }
+
+	     //fall back to postfix
+	     return operand + op;
+
+	   case 2: //binary operators
+	     var lhs = args[0]; //left hand side
+	     //reminder: if parens[0] is false, this puts it in curly braces
+	     var lhsTex = latex.addBraces(lhs.toTex(callbacks), parens[0]);
+	     var rhs = args[1]; //right hand side
+	     var rhsTex = latex.addBraces(rhs.toTex(callbacks), parens[1]);
+
+	     switch (this.getIdentifier()) {
+	       case 'OperatorNode:divide':
+	         //op contains '\\frac' at this point
+	         return op + lhsTex + rhsTex;
+
+	       case 'OperatorNode:to':
+	         rhsTex = latex.toUnit(rhs.toTex(callbacks));
+	         rhsTex = latex.addBraces(rhsTex, parens[1]);
+	         break;
+	     }
+	     return lhsTex + ' ' + op + ' ' + rhsTex;
+
+	   default:
+	     //fall back to formatting as a function call
+	     var argumentList = this.args.map(latex.toSymbol).join(', ');
+	     return latex.toFunction(this.fn) + latex.addBraces(argumentList, true);
+	 }
+	};
+
+	/**
+	 * Get identifier.
+	 * @return {String}
+	 */
+	OperatorNode.prototype.getIdentifier = function () {
+	  return this.type + ':' + this.fn;
 	};
 
 	module.exports = OperatorNode;
 
 
 /***/ },
-/* 182 */
+/* 186 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
-	var Node = __webpack_require__(180);
+	var Node = __webpack_require__(184);
+	var operators = __webpack_require__(341);
 
 	var isNode = Node.isNode;
 
@@ -23789,26 +27517,48 @@
 	 * @return {String} str
 	 */
 	RangeNode.prototype.toString = function() {
-	  // format the range like "start:step:end"
-	  var str = this.start.toString();
+	  var precedence = operators.getPrecedence(this);
+
+	  //format string as start:step:stop
+	  var str;
+
+	  var start = this.start.toString();
+	  var startPrecedence = operators.getPrecedence(this.start);
+	  if ((startPrecedence !== null) && (startPrecedence <= precedence)) {
+	    start = '(' + start + ')';
+	  }
+	  str = start;
+
 	  if (this.step) {
-	    str += ':' + this.step.toString();
-	  }
-	  str += ':' + this.end.toString();
+	    var step = this.step.toString();
+	    var stepPrecedence = operators.getPrecedence(this.step);
+	    if ((stepPrecedence !== null) && (stepPrecedence <= precedence)) {
+	      step = '(' + step + ')';
+	    }
+	    str += ':' + step;
+	  }
+
+	  var end = this.end.toString();
+	  var endPrecedence = operators.getPrecedence(this.end);
+	  if ((endPrecedence !== null) && (endPrecedence <= precedence)) {
+	    end = '(' + end + ')';
+	  }
+	  str += ':' + end;
 
 	  return str;
 	};
 
 	/**
 	 * Get LaTeX representation
+	 * @params {Object|function} callback(s)
 	 * @return {String} str
 	 */
-	RangeNode.prototype.toTex = function() {
-	  var str = this.start.toTex();
+	RangeNode.prototype._toTex = function(callbacks) {
+	  var str = this.start.toTex(callbacks);
 	  if (this.step) {
-	    str += ':' + this.step.toTex();
+	    str += ':' + this.step.toTex(callbacks);
 	  }
-	  str += ':' + this.end.toTex();
+	  str += ':' + this.end.toTex(callbacks);
 
 	  return str;
 	};
@@ -23817,16 +27567,16 @@
 
 
 /***/ },
-/* 183 */
+/* 187 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
-	var Node = __webpack_require__(180),
+	var Node = __webpack_require__(184),
 	    Unit = __webpack_require__(11),
 
-	    latex = __webpack_require__(338),
-	    isString = __webpack_require__(205).isString;
+	    latex = __webpack_require__(342),
+	    isString = __webpack_require__(175).isString;
 
 	/**
 	 * @constructor SymbolNode
@@ -23921,24 +27671,25 @@
 
 	/**
 	 * Get LaTeX representation
+	 * @param {Object|function} callback(s)
 	 * @return {String} str
 	 * @override
 	 */
-	SymbolNode.prototype.toTex = function() {
-	  return latex.toSymbol(this.name);
+	SymbolNode.prototype._toTex = function(callbacks) {
+	  return latex.toSymbol(this.name, callbacks);
 	};
 
 	module.exports = SymbolNode;
 
 
 /***/ },
-/* 184 */
+/* 188 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
-	var Node = __webpack_require__(180),
-	    IndexNode = __webpack_require__(177);
+	var Node = __webpack_require__(184),
+	    IndexNode = __webpack_require__(181);
 
 	/**
 	 * @constructor UpdateNode
@@ -24021,17 +27772,18 @@
 
 	/**
 	 * Get LaTeX representation
+	 * @param {Object|function} callback(s)
 	 * @return {String}
 	 */
-	UpdateNode.prototype.toTex = function() {
-	  return this.index.toTex() + ' = ' + this.expr.toTex();
+	UpdateNode.prototype._toTex = function(callbacks) {
+	  return this.index.toTex(callbacks) + ' = ' + this.expr.toTex(callbacks);
 	};
 
 	module.exports = UpdateNode;
 
 
 /***/ },
-/* 185 */
+/* 189 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -24052,7 +27804,7 @@
 
 
 /***/ },
-/* 186 */
+/* 190 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -24070,7 +27822,7 @@
 
 
 /***/ },
-/* 187 */
+/* 191 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -24090,7 +27842,7 @@
 
 
 /***/ },
-/* 188 */
+/* 192 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -24109,7 +27861,7 @@
 
 
 /***/ },
-/* 189 */
+/* 193 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -24128,7 +27880,7 @@
 
 
 /***/ },
-/* 190 */
+/* 194 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -24147,7 +27899,7 @@
 
 
 /***/ },
-/* 191 */
+/* 195 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -24166,7 +27918,7 @@
 
 
 /***/ },
-/* 192 */
+/* 196 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -24185,7 +27937,7 @@
 
 
 /***/ },
-/* 193 */
+/* 197 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -24204,7 +27956,7 @@
 
 
 /***/ },
-/* 194 */
+/* 198 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -24222,7 +27974,7 @@
 
 
 /***/ },
-/* 195 */
+/* 199 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -24241,7 +27993,7 @@
 
 
 /***/ },
-/* 196 */
+/* 200 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -24259,7 +28011,7 @@
 
 
 /***/ },
-/* 197 */
+/* 201 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -24278,7 +28030,7 @@
 
 
 /***/ },
-/* 198 */
+/* 202 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -24297,7 +28049,7 @@
 
 
 /***/ },
-/* 199 */
+/* 203 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -24316,7 +28068,7 @@
 
 
 /***/ },
-/* 200 */
+/* 204 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -24334,7 +28086,7 @@
 
 
 /***/ },
-/* 201 */
+/* 205 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -24352,28 +28104,28 @@
 
 
 /***/ },
-/* 202 */
+/* 206 */
 /***/ function(module, exports, __webpack_require__) {
 
 	var map = {
-		"./clone": 155,
-		"./clone.js": 155,
-		"./filter": 156,
-		"./filter.js": 156,
-		"./forEach": 163,
-		"./forEach.js": 163,
-		"./format": 157,
-		"./format.js": 157,
-		"./import": 158,
-		"./import.js": 158,
-		"./map": 159,
-		"./map.js": 159,
-		"./print": 160,
-		"./print.js": 160,
-		"./sort": 161,
-		"./sort.js": 161,
-		"./typeof": 162,
-		"./typeof.js": 162
+		"./clone": 158,
+		"./clone.js": 158,
+		"./filter": 159,
+		"./filter.js": 159,
+		"./forEach": 166,
+		"./forEach.js": 166,
+		"./format": 160,
+		"./format.js": 160,
+		"./import": 161,
+		"./import.js": 161,
+		"./map": 162,
+		"./map.js": 162,
+		"./print": 163,
+		"./print.js": 163,
+		"./sort": 164,
+		"./sort.js": 164,
+		"./typeof": 165,
+		"./typeof.js": 165
 	};
 	function webpackContext(req) {
 		return __webpack_require__(webpackContextResolve(req));
@@ -24386,15 +28138,15 @@
 	};
 	webpackContext.resolve = webpackContextResolve;
 	module.exports = webpackContext;
-	webpackContext.id = 202;
+	webpackContext.id = 206;
 
 
 /***/ },
-/* 203 */
+/* 207 */
 /***/ function(module, exports, __webpack_require__) {
 
-	var DimensionError = __webpack_require__(168);
-	var IndexError = __webpack_require__(169);
+	var DimensionError = __webpack_require__(171);
+	var IndexError = __webpack_require__(172);
 
 	/**
 	 * Transform zero-based indices to one-based indices in errors
@@ -24411,7 +28163,7 @@
 
 
 /***/ },
-/* 204 */
+/* 208 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
@@ -24427,122 +28179,7 @@
 
 
 /***/ },
-/* 205 */
-/***/ function(module, exports, __webpack_require__) {
-
-	'use strict';
-
-	var number = __webpack_require__(3);
-	var bignumber = __webpack_require__(164);
-	var BigNumber = __webpack_require__(5);
-
-	/**
-	 * Test whether value is a String
-	 * @param {*} value
-	 * @return {Boolean} isString
-	 */
-	exports.isString = function(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(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.
-	 *
-	 * Usage:
-	 *     math.format(value)
-	 *     math.format(value, precision)
-	 *
-	 * If value is a function, the returned string is 'function' unless the function
-	 * has a property `description`, in that case this properties value is returned.
-	 *
-	 * Example usage:
-	 *     math.format(2/7);                // '0.2857142857142857'
-	 *     math.format(math.pi, 3);         // '3.14'
-	 *     math.format(new Complex(2, 3));  // '2 + 3i'
-	 *     math.format('hello');            // '"hello"'
-	 *
-	 * @param {*} value             Value to be stringified
-	 * @param {Object | Number | Function} [options]  Formatting options. See
-	 *                                                lib/util/number:format for a
-	 *                                                description of the available
-	 *                                                options.
-	 * @return {String} str
-	 */
-	exports.format = function(value, options) {
-	  if (number.isNumber(value)) {
-	    return number.format(value, options);
-	  }
-
-	  if (value instanceof BigNumber) {
-	    return bignumber.format(value, options);
-	  }
-
-	  if (Array.isArray(value)) {
-	    return formatArray(value, options);
-	  }
-
-	  if (exports.isString(value)) {
-	    return '"' + value + '"';
-	  }
-
-	  if (typeof value === 'function') {
-	    return value.syntax ? value.syntax + '' : 'function';
-	  }
-
-	  if (value instanceof Object) {
-	    if (typeof value.format === 'function') {
-	      return value.format(options);
-	    }
-	    else {
-	      return value.toString();
-	    }
-	  }
-
-	  return String(value);
-	};
-
-	/**
-	 * Recursively format an n-dimensional matrix
-	 * Example output: "[[1, 2], [3, 4]]"
-	 * @param {Array} array
-	 * @param {Object | Number | Function} [options]  Formatting options. See
-	 *                                                lib/util/number:format for a
-	 *                                                description of the available
-	 *                                                options.
-	 * @returns {String} str
-	 */
-	function formatArray (array, options) {
-	  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], options);
-	    }
-	    str += ']';
-	    return str;
-	  }
-	  else {
-	    return exports.format(array, options);
-	  }
-	}
-
-
-/***/ },
-/* 206 */
+/* 209 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -24561,7 +28198,7 @@
 
 
 /***/ },
-/* 207 */
+/* 210 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -24586,7 +28223,7 @@
 
 
 /***/ },
-/* 208 */
+/* 211 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -24607,7 +28244,7 @@
 
 
 /***/ },
-/* 209 */
+/* 212 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -24631,7 +28268,7 @@
 
 
 /***/ },
-/* 210 */
+/* 213 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -24657,7 +28294,7 @@
 
 
 /***/ },
-/* 211 */
+/* 214 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -24682,7 +28319,7 @@
 
 
 /***/ },
-/* 212 */
+/* 215 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -24707,7 +28344,7 @@
 
 
 /***/ },
-/* 213 */
+/* 216 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -24730,7 +28367,7 @@
 
 
 /***/ },
-/* 214 */
+/* 217 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -24755,7 +28392,7 @@
 
 
 /***/ },
-/* 215 */
+/* 218 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -24777,7 +28414,7 @@
 
 
 /***/ },
-/* 216 */
+/* 219 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -24798,7 +28435,7 @@
 
 
 /***/ },
-/* 217 */
+/* 220 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -24819,7 +28456,7 @@
 
 
 /***/ },
-/* 218 */
+/* 221 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -24839,7 +28476,7 @@
 
 
 /***/ },
-/* 219 */
+/* 222 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -24867,7 +28504,7 @@
 	};
 
 /***/ },
-/* 220 */
+/* 223 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -24892,7 +28529,7 @@
 
 
 /***/ },
-/* 221 */
+/* 224 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -24918,7 +28555,7 @@
 
 
 /***/ },
-/* 222 */
+/* 225 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -24943,7 +28580,7 @@
 
 
 /***/ },
-/* 223 */
+/* 226 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -24969,7 +28606,7 @@
 
 
 /***/ },
-/* 224 */
+/* 227 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -24995,7 +28632,7 @@
 	};
 
 /***/ },
-/* 225 */
+/* 228 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -25017,7 +28654,7 @@
 
 
 /***/ },
-/* 226 */
+/* 229 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -25042,7 +28679,7 @@
 
 
 /***/ },
-/* 227 */
+/* 230 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -25065,7 +28702,7 @@
 
 
 /***/ },
-/* 228 */
+/* 231 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -25089,7 +28726,7 @@
 
 
 /***/ },
-/* 229 */
+/* 232 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -25116,7 +28753,7 @@
 
 
 /***/ },
-/* 230 */
+/* 233 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -25141,7 +28778,7 @@
 
 
 /***/ },
-/* 231 */
+/* 234 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -25165,7 +28802,7 @@
 
 
 /***/ },
-/* 232 */
+/* 235 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -25188,7 +28825,7 @@
 
 
 /***/ },
-/* 233 */
+/* 236 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -25208,7 +28845,7 @@
 
 
 /***/ },
-/* 234 */
+/* 237 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -25231,7 +28868,7 @@
 
 
 /***/ },
-/* 235 */
+/* 238 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -25254,7 +28891,7 @@
 
 
 /***/ },
-/* 236 */
+/* 239 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -25276,7 +28913,7 @@
 
 
 /***/ },
-/* 237 */
+/* 240 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -25297,7 +28934,7 @@
 
 
 /***/ },
-/* 238 */
+/* 241 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -25319,7 +28956,7 @@
 
 
 /***/ },
-/* 239 */
+/* 242 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -25342,7 +28979,7 @@
 
 
 /***/ },
-/* 240 */
+/* 243 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -25365,7 +29002,7 @@
 
 
 /***/ },
-/* 241 */
+/* 244 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -25391,7 +29028,7 @@
 
 
 /***/ },
-/* 242 */
+/* 245 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -25417,7 +29054,7 @@
 
 
 /***/ },
-/* 243 */
+/* 246 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -25443,7 +29080,7 @@
 
 
 /***/ },
-/* 244 */
+/* 247 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -25469,7 +29106,7 @@
 
 
 /***/ },
-/* 245 */
+/* 248 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -25494,7 +29131,7 @@
 
 
 /***/ },
-/* 246 */
+/* 249 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -25521,7 +29158,7 @@
 
 
 /***/ },
-/* 247 */
+/* 250 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -25546,7 +29183,7 @@
 
 
 /***/ },
-/* 248 */
+/* 251 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -25577,7 +29214,7 @@
 
 
 /***/ },
-/* 249 */
+/* 252 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -25605,7 +29242,7 @@
 
 
 /***/ },
-/* 250 */
+/* 253 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -25634,7 +29271,7 @@
 
 
 /***/ },
-/* 251 */
+/* 254 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -25658,7 +29295,7 @@
 
 
 /***/ },
-/* 252 */
+/* 255 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -25684,7 +29321,7 @@
 
 
 /***/ },
-/* 253 */
+/* 256 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -25704,7 +29341,7 @@
 
 
 /***/ },
-/* 254 */
+/* 257 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -25724,7 +29361,7 @@
 
 
 /***/ },
-/* 255 */
+/* 258 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -25747,7 +29384,7 @@
 
 
 /***/ },
-/* 256 */
+/* 259 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -25772,7 +29409,7 @@
 
 
 /***/ },
-/* 257 */
+/* 260 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -25795,7 +29432,7 @@
 
 
 /***/ },
-/* 258 */
+/* 261 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -25819,7 +29456,7 @@
 
 
 /***/ },
-/* 259 */
+/* 262 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -25844,7 +29481,7 @@
 
 
 /***/ },
-/* 260 */
+/* 263 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -25867,7 +29504,7 @@
 
 
 /***/ },
-/* 261 */
+/* 264 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -25888,7 +29525,7 @@
 
 
 /***/ },
-/* 262 */
+/* 265 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -25912,7 +29549,7 @@
 
 
 /***/ },
-/* 263 */
+/* 266 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -25936,7 +29573,7 @@
 
 
 /***/ },
-/* 264 */
+/* 267 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -25962,7 +29599,7 @@
 
 
 /***/ },
-/* 265 */
+/* 268 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -25985,7 +29622,7 @@
 
 
 /***/ },
-/* 266 */
+/* 269 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -26007,7 +29644,7 @@
 
 
 /***/ },
-/* 267 */
+/* 270 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -26037,7 +29674,7 @@
 
 
 /***/ },
-/* 268 */
+/* 271 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -26068,7 +29705,7 @@
 
 
 /***/ },
-/* 269 */
+/* 272 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -26093,7 +29730,7 @@
 
 
 /***/ },
-/* 270 */
+/* 273 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -26117,7 +29754,7 @@
 
 
 /***/ },
-/* 271 */
+/* 274 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -26140,7 +29777,7 @@
 
 
 /***/ },
-/* 272 */
+/* 275 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -26171,7 +29808,7 @@
 
 
 /***/ },
-/* 273 */
+/* 276 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -26192,7 +29829,7 @@
 
 
 /***/ },
-/* 274 */
+/* 277 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -26215,7 +29852,7 @@
 
 
 /***/ },
-/* 275 */
+/* 278 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -26244,7 +29881,7 @@
 
 
 /***/ },
-/* 276 */
+/* 279 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -26262,7 +29899,7 @@
 
 
 /***/ },
-/* 277 */
+/* 280 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -26283,7 +29920,7 @@
 
 
 /***/ },
-/* 278 */
+/* 281 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -26304,7 +29941,7 @@
 
 
 /***/ },
-/* 279 */
+/* 282 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -26324,7 +29961,7 @@
 
 
 /***/ },
-/* 280 */
+/* 283 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -26344,7 +29981,7 @@
 
 
 /***/ },
-/* 281 */
+/* 284 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -26370,7 +30007,7 @@
 
 
 /***/ },
-/* 282 */
+/* 285 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -26395,7 +30032,7 @@
 	};
 
 /***/ },
-/* 283 */
+/* 286 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -26420,7 +30057,7 @@
 
 
 /***/ },
-/* 284 */
+/* 287 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -26442,7 +30079,7 @@
 
 
 /***/ },
-/* 285 */
+/* 288 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -26469,7 +30106,7 @@
 
 
 /***/ },
-/* 286 */
+/* 289 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -26497,7 +30134,7 @@
 
 
 /***/ },
-/* 287 */
+/* 290 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -26523,7 +30160,7 @@
 
 
 /***/ },
-/* 288 */
+/* 291 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -26550,7 +30187,7 @@
 
 
 /***/ },
-/* 289 */
+/* 292 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -26576,7 +30213,7 @@
 
 
 /***/ },
-/* 290 */
+/* 293 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -26604,7 +30241,7 @@
 
 
 /***/ },
-/* 291 */
+/* 294 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -26638,7 +30275,7 @@
 
 
 /***/ },
-/* 292 */
+/* 295 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -26671,7 +30308,7 @@
 
 
 /***/ },
-/* 293 */
+/* 296 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -26699,7 +30336,7 @@
 
 
 /***/ },
-/* 294 */
+/* 297 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -26733,7 +30370,7 @@
 
 
 /***/ },
-/* 295 */
+/* 298 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -26763,7 +30400,7 @@
 
 
 /***/ },
-/* 296 */
+/* 299 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -26796,7 +30433,7 @@
 
 
 /***/ },
-/* 297 */
+/* 300 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -26826,7 +30463,7 @@
 
 
 /***/ },
-/* 298 */
+/* 301 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -26859,7 +30496,7 @@
 
 
 /***/ },
-/* 299 */
+/* 302 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -26882,7 +30519,7 @@
 
 
 /***/ },
-/* 300 */
+/* 303 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -26903,7 +30540,7 @@
 	};
 
 /***/ },
-/* 301 */
+/* 304 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -26926,7 +30563,7 @@
 
 
 /***/ },
-/* 302 */
+/* 305 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -26946,7 +30583,7 @@
 	};
 
 /***/ },
-/* 303 */
+/* 306 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -26970,7 +30607,7 @@
 
 
 /***/ },
-/* 304 */
+/* 307 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -26991,7 +30628,7 @@
 
 
 /***/ },
-/* 305 */
+/* 308 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -27015,7 +30652,7 @@
 
 
 /***/ },
-/* 306 */
+/* 309 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -27036,7 +30673,7 @@
 
 
 /***/ },
-/* 307 */
+/* 310 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -27059,7 +30696,7 @@
 
 
 /***/ },
-/* 308 */
+/* 311 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -27080,7 +30717,7 @@
 
 
 /***/ },
-/* 309 */
+/* 312 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -27103,7 +30740,7 @@
 
 
 /***/ },
-/* 310 */
+/* 313 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -27124,7 +30761,7 @@
 
 
 /***/ },
-/* 311 */
+/* 314 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -27151,7 +30788,7 @@
 
 
 /***/ },
-/* 312 */
+/* 315 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -27177,7 +30814,7 @@
 
 
 /***/ },
-/* 313 */
+/* 316 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -27199,7 +30836,7 @@
 
 
 /***/ },
-/* 314 */
+/* 317 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -27222,7 +30859,7 @@
 
 
 /***/ },
-/* 315 */
+/* 318 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -27245,7 +30882,7 @@
 
 
 /***/ },
-/* 316 */
+/* 319 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -27268,7 +30905,7 @@
 
 
 /***/ },
-/* 317 */
+/* 320 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -27291,7 +30928,7 @@
 
 
 /***/ },
-/* 318 */
+/* 321 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -27314,7 +30951,7 @@
 
 
 /***/ },
-/* 319 */
+/* 322 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -27337,7 +30974,7 @@
 
 
 /***/ },
-/* 320 */
+/* 323 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -27363,7 +31000,7 @@
 
 
 /***/ },
-/* 321 */
+/* 324 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -27384,7 +31021,7 @@
 
 
 /***/ },
-/* 322 */
+/* 325 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -27409,7 +31046,7 @@
 
 
 /***/ },
-/* 323 */
+/* 326 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -27431,7 +31068,7 @@
 
 
 /***/ },
-/* 324 */
+/* 327 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -27452,7 +31089,7 @@
 
 
 /***/ },
-/* 325 */
+/* 328 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -27474,7 +31111,7 @@
 
 
 /***/ },
-/* 326 */
+/* 329 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -27492,7 +31129,7 @@
 
 
 /***/ },
-/* 327 */
+/* 330 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -27512,7 +31149,7 @@
 
 
 /***/ },
-/* 328 */
+/* 331 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -27530,7 +31167,7 @@
 
 
 /***/ },
-/* 329 */
+/* 332 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -27552,7 +31189,7 @@
 
 
 /***/ },
-/* 330 */
+/* 333 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -27571,7 +31208,7 @@
 
 
 /***/ },
-/* 331 */
+/* 334 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -27593,7 +31230,7 @@
 
 
 /***/ },
-/* 332 */
+/* 335 */
 /***/ function(module, exports, __webpack_require__) {
 
 	module.exports = {
@@ -27614,7 +31251,7 @@
 
 
 /***/ },
-/* 333 */
+/* 336 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
@@ -27623,9 +31260,9 @@
 	// TODO: rethink math.distribution
 
 	module.exports = function (math) {
-	  var Matrix = __webpack_require__(10);
-	  var array = __webpack_require__(165);
-	  var collection = __webpack_require__(14);
+	  var Matrix = math.type.Matrix;
+	  var array = __webpack_require__(168);
+	  var collection = math.collection;
 	  var isCollection = collection.isCollection;
 
 	  /**
@@ -27699,7 +31336,7 @@
 	          if (min === undefined) min = 0;
 	          if (size !== undefined) {
 	            var res = _randomDataForMatrix(size.valueOf(), min, max, _random);
-	            return (size instanceof Matrix) ? new Matrix(res) : res;
+	            return (size instanceof Matrix) ? math.matrix(res) : res;
 	          }
 	          else return _random(min, max);
 	        },
@@ -27739,7 +31376,7 @@
 	          if (min === undefined) min = 0;
 	          if (size !== undefined) {
 	            var res = _randomDataForMatrix(size.valueOf(), min, max, _randomInt);
-	            return (size instanceof Matrix) ? new Matrix(res) : res;
+	            return (size instanceof Matrix) ? math.matrix(res) : res;
 	          }
 	          else return _randomInt(min, max);
 	        },
@@ -27827,7 +31464,7 @@
 
 
 /***/ },
-/* 334 */
+/* 337 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
@@ -27860,7 +31497,7 @@
 
 
 /***/ },
-/* 335 */
+/* 338 */
 /***/ function(module, exports, __webpack_require__) {
 
 	// function utils
@@ -27889,7 +31526,7 @@
 
 
 /***/ },
-/* 336 */
+/* 339 */
 /***/ function(module, exports, __webpack_require__) {
 
 	var __WEBPACK_AMD_DEFINE_RESULT__;/*! decimal.js v4.0.2 https://github.com/MikeMcl/decimal.js/LICENCE */
@@ -29397,15 +33034,15 @@
 	     * ECMAScript compliant.
 	     *
 	     *   x is any value, including NaN.
-	     *   n is any number, including �Infinity unless stated.
+	     *   n is any number, including �Infinity unless stated.
 	     *
 	     *   pow( x, NaN )                           = NaN
-	     *   pow( x, �0 )                            = 1
+	     *   pow( x, �0 )                            = 1
 
 	     *   pow( NaN, nonzero )                     = NaN
 	     *   pow( abs(n) > 1, +Infinity )            = +Infinity
 	     *   pow( abs(n) > 1, -Infinity )            = +0
-	     *   pow( abs(n) == 1, �Infinity )           = NaN
+	     *   pow( abs(n) == 1, �Infinity )           = NaN
 	     *   pow( abs(n) < 1, +Infinity )            = +0
 	     *   pow( abs(n) < 1, -Infinity )            = +Infinity
 	     *   pow( +Infinity, n > 0 )                 = +Infinity
@@ -31955,7 +35592,7 @@
 
 
 /***/ },
-/* 337 */
+/* 340 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
@@ -31967,16 +35604,294 @@
 
 
 /***/ },
-/* 338 */
+/* 341 */
+/***/ function(module, exports, __webpack_require__) {
+
+	'use strict'
+
+	//list of identifiers of nodes in order of their precedence
+	//also contains information about left/right associativity
+	//and which other operator the operator is associative with
+	//Example:
+	// addition is associative with addition and subtraction, because:
+	// (a+b)+c=a+(b+c)
+	// (a+b)-c=a+(b-c)
+	//
+	// postfix operators are left associative, prefix operators 
+	// are right associative
+	var properties = [
+	  { //assignment
+	    'AssignmentNode': {},
+	    'FunctionAssignmentNode': {}
+	  },
+	  { //conditional expression
+	    'ConditionalNode': {}
+	  },
+	  { //logical or
+	    'OperatorNode:or': {
+	      associativity: 'left',
+	      associativeWith: []
+	    }
+
+	  },
+	  { //logical xor
+	    'OperatorNode:xor': {
+	      associativity: 'left',
+	      associativeWith: []
+	    }
+	  },
+	  { //logical and
+	    'OperatorNode:and': {
+	      associativity: 'left',
+	      associativeWith: []
+	    }
+	  },
+	  { //bitwise or
+	    'OperatorNode:bitOr': {
+	      associativity: 'left',
+	      associativeWith: []
+	    }
+	  },
+	  { //bitwise xor
+	    'OperatorNode:bitXor': {
+	      associativity: 'left',
+	      associativeWith: []
+	    }
+	  },
+	  { //bitwise and
+	    'OperatorNode:bitAnd': {
+	      associativity: 'left',
+	      associativeWith: []
+	    }
+	  },
+	  { //relational operators
+	    'OperatorNode:equal': {
+	      associativity: 'left',
+	      associativeWith: []
+	    },
+	    'OperatorNode:unequal': {
+	      associativity: 'left',
+	      associativeWith: []
+	    },
+	    'OperatorNode:smaller': {
+	      associativity: 'left',
+	      associativeWith: []
+	    },
+	    'OperatorNode:larger': {
+	      associativity: 'left',
+	      associativeWith: []
+	    },
+	    'OperatorNode:smallerEq': {
+	      associativity: 'left',
+	      associativeWith: []
+	    },
+	    'OperatorNode:largerEq': {
+	      associativity: 'left',
+	      associativeWith: []
+	    }
+	  },
+	  { //bitshift operators
+	    'OperatorNode:leftShift': {
+	      associativity: 'left',
+	      associativeWith: []
+	    },
+	    'OperatorNode:rightArithShift': {
+	      associativity: 'left',
+	      associativeWith: []
+	    },
+	    'OperatorNode:rightLogShift': {
+	      associativity: 'left',
+	      associativeWith: []
+	    }
+	  },
+	  { //unit conversion
+	    'OperatorNode:to': {
+	      associativity: 'left',
+	      associativeWith: []
+	    }
+	  },
+	  { //range
+	    'RangeNode': {}
+	  },
+	  { //addition, subtraction
+	    'OperatorNode:add': {
+	      associativity: 'left',
+	      associativeWith: ['OperatorNode:add', 'OperatorNode:subtract']
+	    },
+	    'OperatorNode:subtract': {
+	      associativity: 'left',
+	      associativeWith: []
+	    }
+	  },
+	  { //multiply, divide, modulus
+	    'OperatorNode:multiply': {
+	      associativity: 'left',
+	      associativeWith: [
+	        'OperatorNode:multiply',
+	        'OperatorNode:divide',
+	        'Operator:dotMultiply',
+	        'Operator:dotDivide'
+	      ]
+	    },
+	    'OperatorNode:divide': {
+	      associativity: 'left',
+	      associativeWith: []
+	    },
+	    'OperatorNode:dotMultiply': {
+	      associativity: 'left',
+	      associativeWith: [
+	        'OperatorNode:multiply',
+	        'OperatorNode:divide',
+	        'OperatorNode:dotMultiply',
+	        'OperatorNode:doDivide'
+	      ]
+	    },
+	    'OperatorNode:dotDivide': {
+	      associativity: 'left',
+	      associativeWith: []
+	    },
+	    'OperatorNode:mod': {
+	      associativity: 'left',
+	      associativeWith: []
+	    }
+	  },
+	  { //unary prefix operators
+	    'OperatorNode:unaryPlus': {
+	      associativity: 'right'
+	    },
+	    'OperatorNode:unaryMinus': {
+	      associativity: 'right'
+	    },
+	    'OperatorNode:bitNot': {
+	      associativity: 'right'
+	    },
+	    'OperatorNode:not': {
+	      associativity: 'right'
+	    }
+	  },
+	  { //exponentiation
+	    'OperatorNode:pow': {
+	      associativity: 'right',
+	      associativeWith: []
+	    },
+	    'OperatorNode:dotPow': {
+	      associativity: 'right',
+	      associativeWith: []
+	    }
+	  },
+	  { //factorial
+	    'OperatorNode:factorial': {
+	      associativity: 'left'
+	    }
+	  },
+	  { //matrix transpose
+	    'OperatorNode:transpose': {
+	      associativity: 'left'
+	    }
+	  }
+	];
+
+	/**
+	 * Get the precedence of a Node.
+	 * Higher number for higher precedence, starting with 0.
+	 * Returns null if the precedence is undefined.
+	 *
+	 * @param {Node}
+	 * @return {Number|null}
+	 */
+	function getPrecedence (node) {
+	  var identifier = node.getIdentifier();
+	  for (var i = 0; i < properties.length; i++) {
+	    if (identifier in properties[i]) {
+	      return i;
+	    }
+	  }
+	  return null;
+	}
+
+	/**
+	 * Get the associativity of an operator (left or right).
+	 * Returns a string containing 'left' or 'right' or null if
+	 * the associativity is not defined.
+	 *
+	 * @param {Node}
+	 * @return {String|null}
+	 * @throws {Error}
+	 */
+	function getAssociativity (node) {
+	  var identifier = node.getIdentifier();
+	  var index = getPrecedence(node);
+	  if (index === null) {
+	    //node isn't in the list
+	    return null;
+	  }
+	  var property = properties[index][identifier];
+
+	  if (property.hasOwnProperty('associativity')) {
+	    if (property.associativity === 'left') {
+	      return 'left';
+	    }
+	    if (property.associativity === 'right') {
+	      return 'right';
+	    }
+	    //associativity is invalid
+	    throw Error('\'' + identifier + '\' has the invalid associativity \''
+	                + property.associativity + '\'.');
+	  }
+
+	  //associativity is undefined
+	  return null;
+	}
+
+	/**
+	 * Check if an operator is associative with another operator.
+	 * Returns either true or false or null if not defined.
+	 *
+	 * @param {Node} nodeA
+	 * @param {Node} nodeB
+	 * @return {bool|null}
+	 */
+	function isAssociativeWith (nodeA, nodeB) {
+	  var identifierA = nodeA.getIdentifier();
+	  var identifierB = nodeB.getIdentifier();
+	  var index = getPrecedence(nodeA);
+	  if (index === null) {
+	    //node isn't in the list
+	    return null;
+	  }
+	  var property = properties[index][identifierA];
+
+	  if (property.hasOwnProperty('associativeWith')
+	      && (property.associativeWith instanceof Array)) {
+	    for (var i = 0; i < property.associativeWith.length; i++) {
+	      if (property.associativeWith[i] === identifierB) {
+	        return true;
+	      }
+	    }
+	    return false;
+	  }
+
+	  //associativeWith is not defined
+	  return null;
+	}
+
+	module.exports.properties = properties;
+	module.exports.getPrecedence = getPrecedence;
+	module.exports.getAssociativity = getAssociativity;
+	module.exports.isAssociativeWith = isAssociativeWith;
+
+
+/***/ },
+/* 342 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
 
 	// FIXME: remove dependencies on Nodes
-	var ArrayNode = __webpack_require__(172);
-	var OperatorNode = __webpack_require__(181);
-	var SymbolNode = __webpack_require__(183);
-	var ConstantNode = __webpack_require__(176);
+	var ArrayNode = __webpack_require__(176);
+	var OperatorNode = __webpack_require__(185);
+	var SymbolNode = __webpack_require__(187);
+	var ConstantNode = __webpack_require__(180);
 
 	// GREEK LETTERS
 	var greek = {
@@ -32258,7 +36173,7 @@
 	  return braces[0] + s + braces[1];
 	};
 
-	exports.toArgs = function(that) {
+	exports.toArgs = function(that, customFunctions) {
 	  var name = that.name,
 	      args = that.args,
 	      func = exports.toSymbol(that.name),
@@ -32330,13 +36245,13 @@
 	          op = '!';
 	        }
 	        else {
-	          return '{\\left(' + args[0].toTex() + '\\right)!}';
+	          return '{\\left(' + args[0].toTex(customFunctions) + '\\right)!}';
 	        }
 	      }
 	      else {
 	        // op = 'P';
-	        var n = args[0].toTex(),
-	            k = args[1].toTex();
+	        var n = args[0].toTex(customFunctions),
+	            k = args[1].toTex(customFunctions);
 	        return '\\frac{' + n + '!}{\\left(' + n + ' - ' + k + '\\right)!}';
 	      }
 	      break;
@@ -32357,7 +36272,7 @@
 	      type = 'lr';
 
 	      if (args.length === 2) {
-	        var tmp = args[1].toTex();
+	        var tmp = args[1].toTex(customFunctions);
 
 	        if (tmp === '\\text{inf}') {
 	          tmp = '\\infty';
@@ -32389,7 +36304,7 @@
 	      type = 'lr';
 
 	      if (args.length === 2) {
-	        suffix = '_' + exports.addBraces(args[1].toTex());
+	        suffix = '_' + exports.addBraces(args[1].toTex(customFunctions));
 	        args = [args[0]];
 	      }
 	      break;
@@ -32409,7 +36324,7 @@
 	    case 'log':
 	      var base = 'e';
 	      if (args.length === 2) {
-	        base = args[1].toTex();
+	        base = args[1].toTex(customFunctions);
 	        func = '\\log_{' + base + '}';
 	        args = [args[0]];
 	      }
@@ -32438,7 +36353,11 @@
 
 	    case 'det':
 	      if (that.args[0] instanceof ArrayNode) {
-	        return that.args[0].toTex('vmatrix');
+	        //FIXME passing 'vmatrix' like that is really ugly
+	        that.args[0].latexType = 'vmatrix';
+	        var latex = that.args[0].toTex(customFunctions);
+	        delete that.args[0].latexType;
+	        return latex;
 	      }
 
 	      brace = 'vmatrix';
@@ -32452,7 +36371,7 @@
 
 	  if (op !== null) {
 	    brace = (op === '+' || op === '-');
-	    texParams = (new OperatorNode(op, name, args)).toTex();
+	    texParams = (new OperatorNode(op, name, args)).toTex(customFunctions);
 	  }
 	  else {
 	    op = ', ';
@@ -32463,7 +36382,7 @@
 	  }
 
 	  texParams = texParams || args.map(function(param) {
-	    return '{' + param.toTex() + '}'  ;
+	    return '{' + param.toTex(customFunctions) + '}'  ;
 	  }).join(op);
 
 	  return prefix + (showFunc ? func : '') +
@@ -32475,3 +36394,4 @@
 /***/ }
 /******/ ])
 });
+;


Follow ups