Repository: josdejong/mathjs
Pull request #717 (2016-09-26 01:36:48)

Extend cross() to support n-d vectors
Squeeze arrays before attempting to cross them so that n-dimensional
vectors can be cross multiplied (as long as only one direction has a
series of 3 elements)

See issue #713 


Patch:
diff --git a/lib/function/matrix/cross.js b/lib/function/matrix/cross.js
index 2c58ca475..cfd5c4243 100644
--- a/lib/function/matrix/cross.js
+++ b/lib/function/matrix/cross.js
@@ -1,6 +1,6 @@
 'use strict';
 
-var size = require('../../utils/array').size;
+var array = require('../../utils/array');
 
 function factory (type, config, load, typed) {
   var matrix   = load(require('../../type/matrix/function/matrix'));
@@ -9,7 +9,7 @@ function factory (type, config, load, typed) {
 
   /**
    * Calculate the cross product for two vectors in three dimensional space.
-   * The cross product of `A = [a1, a2, a3]` and `B =[b1, b2, b3]` is defined
+   * The cross product of `A = [a1, a2, a3]` and `B = [b1, b2, b3]` is defined
    * as:
    *
    *    cross(A, B) = [
@@ -18,15 +18,19 @@ function factory (type, config, load, typed) {
    *      a1 * b2 - a2 * b1
    *    ]
    *
+   * If one of the input vectors has a dimension greater than 1, the output
+   * vector will be a 1x3 (2-dimensional) matrix.
+   *
    * Syntax:
    *
    *    math.cross(x, y)
    *
    * Examples:
    *
-   *    math.cross([1, 1, 0],  [0, 1, 1]);  // Returns [1, -1, 1]
-   *    math.cross([3, -3, 1], [4, 9, 2]);  // Returns [-15, -2, 39]
-   *    math.cross([2, 3, 4],  [5, 6, 7]);  // Returns [-3, 6, -3]
+   *    math.cross([1, 1, 0],   [0, 1, 1]);       // Returns [1, -1, 1]
+   *    math.cross([3, -3, 1],  [4, 9, 2]);       // Returns [-15, -2, 39]
+   *    math.cross([2, 3, 4],   [5, 6, 7]);       // Returns [-3, 6, -3]
+   *    math.cross([[1, 2, 3]], [[4], [5], [6]]); // Returns [[-3, 6, -3]]
    *
    * See also:
    *
@@ -66,19 +70,30 @@ function factory (type, config, load, typed) {
    * @private
    */
   function _cross(x, y) {
-    var xSize= size(x);
-    var ySize = size(y);
+    var highestDimension = Math.max(array.size(x).length, array.size(y).length);
+
+    x = array.squeeze(x);
+    y = array.squeeze(y);
+
+    var xSize = array.size(x);
+    var ySize = array.size(y);
 
     if (xSize.length != 1 || ySize.length != 1 || xSize[0] != 3 || ySize[0] != 3) {
       throw new RangeError('Vectors with length 3 expected ' +
       '(Size A = [' + xSize.join(', ') + '], B = [' + ySize.join(', ') + '])');
     }
 
-    return [
+    var product = [
       subtract(multiply(x[1], y[2]), multiply(x[2], y[1])),
       subtract(multiply(x[2], y[0]), multiply(x[0], y[2])),
       subtract(multiply(x[0], y[1]), multiply(x[1], y[0]))
     ];
+
+    if (highestDimension > 1) {
+      return [product];
+    } else {
+      return product;
+    }
   }
 }
 


Test patch:
diff --git a/test/function/matrix/cross.test.js b/test/function/matrix/cross.test.js
index f96169b40..51d418a02 100644
--- a/test/function/matrix/cross.test.js
+++ b/test/function/matrix/cross.test.js
@@ -22,6 +22,12 @@ describe('cross', function() {
         math.matrix([1, -1, 1]));
   });
 
+  it('should calculate cross product for n-d arrays and matrices', function () {
+    assert.deepEqual(math.cross([[1, 2, 3]], [[4, 5, 6]]), [[-3, 6, -3]]);
+    assert.deepEqual(math.cross([[1], [2], [3]], [4, 5, 6]), [[-3, 6, -3]]);
+    assert.deepEqual(math.cross([[[[1, 2, 3]]]], [[4, 5, 6]]), [[-3, 6, -3]]);
+  });
+
   it('should throw an error for unsupported types of arguments', function() {
     assert.throws(function () {math.cross([2, 4, 1], 2)}, TypeError);
   });