Home Reference Source Repository

src/dot.js

import dim from './dim'
import add from './add'
import sub from './sub'
import Complex from './Complex'

/**
 * 
 * 
 * @export
 * @param {Array | Number} x
 * @param {Array | Number} y
 * @returns {Array | Number}
 * @example
 * 
 * dot([[1, 1], [2, 1]], [1, 2])
 * // [3, 4]
 * 
 * dot([1, 2], 4)
 * // [4, 8]
 */
export default function (x, y) {
  switch (x.constructor.name) {
    case 'Complex':
      return cdot(x, y);
    case 'Sparse':
      return sdot(x, y);
    default:
      return dot(x, y);
  }
}

function cdot(x, y) {
  if (!(y instanceof Complex)) { y = new Complex(y); }
    if (x.im) {
      if (y.im) {
        return new Complex(sub(dot(x.re, y.re), dot(x.im, y.im)), add(dot(x.re, y.im), dot(x.im, y.re)));
      }
      return new Complex(dot(x.re, y.re), dot(x.im, y.re));
    }
    if (y.im) {
      return new Complex(dot(x.re, y.re), dot(x.re, y.im));
    }
    return new Complex(dot(x.re, y.re));
}

function sdot(x, y) {
    // TODO
  throw new Error('mathlab.dot: dot for sparse matrix not exist')
}

function dot(x, y) {
    var d = dim;
    switch (d(x).length * 1000 + d(y).length) {
        case 2002:
            if (y.length < 10) return dotMMsmall(x, y);
            else return dotMMbig(x, y);
        case 2001:
            return dotMV(x, y);
        case 1002:
            return dotVM(x, y);
        case 1001:
            return dotVV(x, y);
        case 1000:
            return mulVS(x, y);
        case 1:
            return mulSV(x, y);
        case 0:
            return x * y;
        default:
            throw new Error('dot only works on vectors and matrices');
    }
}


function dotMMsmall(x, y) {
    var i, j, k, p, q, r, ret, foo, bar, woo, i0, k0, p0, r0;
    p = x.length;
    q = y.length;
    r = y[0].length;
    ret = Array(p);
    for (i = p - 1; i >= 0; i--) {
        foo = Array(r);
        bar = x[i];
        for (k = r - 1; k >= 0; k--) {
            woo = bar[q - 1] * y[q - 1][k];
            for (j = q - 2; j >= 1; j -= 2) {
                i0 = j - 1;
                woo += bar[j] * y[j][k] + bar[i0] * y[i0][k];
            }
            if (j === 0) {
                woo += bar[0] * y[0][k];
            }
            foo[k] = woo;
        }
        ret[i] = foo;
    }
    return ret;
}

function _getCol(A, j, x) {
    var n = A.length,
        i;
    for (i = n - 1; i > 0; --i) {
        x[i] = A[i][j];
        --i;
        x[i] = A[i][j];
    }
    if (i === 0) x[0] = A[0][j];
}

function dotMMbig(x, y) {
    var gc = _getCol,
        p = y.length,
        v = Array(p);
    var m = x.length,
        n = y[0].length,
        A = new Array(m),
        xj;
    var VV = dotVV;
    var i, j, k, z;
    --p;
    --m;
    for (i = m; i !== -1; --i) A[i] = Array(n);
    --n;
    for (i = n; i !== -1; --i) {
        gc(y, i, v);
        for (j = m; j !== -1; --j) {
            z = 0;
            xj = x[j];
            A[j][i] = VV(xj, v);
        }
    }
    return A;
}

function dotMV(x, y) {
    var p = x.length,
        q = y.length,
        i;
    var ret = Array(p);
    for (i = p - 1; i >= 0; i--) {
        ret[i] = dotVV(x[i], y);
    }
    return ret;
}

function dotVM(x, y) {
    var i, j, k, p, q, r, ret, foo, bar, woo, i0, k0, p0, r0, s1, s2, s3, baz, accum;
    p = x.length;
    q = y[0].length;
    ret = Array(q);
    for (k = q - 1; k >= 0; k--) {
        woo = x[p - 1] * y[p - 1][k];
        for (j = p - 2; j >= 1; j -= 2) {
            i0 = j - 1;
            woo += x[j] * y[j][k] + x[i0] * y[i0][k];
        }
        if (j === 0) {
            woo += x[0] * y[0][k];
        }
        ret[k] = woo;
    }
    return ret;
}

function dotVV(x, y) {
    var i, n = x.length,
        i1, ret = x[n - 1] * y[n - 1];
    for (i = n - 2; i >= 1; i -= 2) {
        i1 = i - 1;
        ret += x[i] * y[i] + x[i1] * y[i1];
    }
    if (i === 0) {
        ret += x[0] * y[0];
    }
    return ret;
}

function mulVV(x, y) {
    var _n = y.length;
    var i, ret = Array(_n);
    for (i = _n - 1; i !== -1; --i) {
        ret[i] = x[i] * y[i]
    }
    return ret;
}

function mulSV(x, y) {
    var _n = y.length;
    var i, ret = Array(_n);
    for (i = _n - 1; i !== -1; --i) {
        ret[i] = x * y[i]
    }
    return ret;
}

function mulVS(x, y) {
    var _n = x.length;
    var i, ret = Array(_n);
    for (i = _n - 1; i !== -1; --i) {
        ret[i] = x[i] * y
    }
    return ret;
}