Home Reference Source

src/libs/util.js

/*
 * Copyright (c) 2018 Isaac Phoenix ([email protected]).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import math from 'mathjs'

/**
 * @ignore
 * generate a n-Length Array filled by `0`
 * @param {number} n
 * @return {number[]}
 */
export function zeros(n) {
  const array = new Array(n)
  for (let i = 0; i < n; ++i) {
    array[i] = 0
  }
  return array
}

/**
 * @ignore
 * check if an array is `tuple`
 * @param {Array} value
 * @return {boolean}
 */
export function arrayIsTuple(value) {
  let isTuple = false
  if (typeof value.$$__tuple !== 'undefined') {
    isTuple = value.$$__tuple
    return isTuple
  }
  if (Array.isArray(value)) {
    isTuple = value.some(item => item instanceof Array)
  }
  return isTuple
}

/**
 * @ignore
 * force mark a value as `tuple`, internal usage only
 * @param value
 */
export function markTuple(value) {
  value.$$__tuple = true
}

/**
 * create `tuple` from arguments
 * @param args
 * @return {Array}
 */
export function tuple(...args) {
  const result = new Array(...args)
  markTuple(result)
  return result
}

/**
 * @ignore
 * create copy of object, with same `class`
 * @param {Object} obj
 * @return {Object}
 */
export function ObjectCopy(obj) {
  const copy = Object.create(obj.__proto__)
  Object.assign(copy, obj)
  return copy
}

/**
 * return class hierachy of `cls`
 * @param {function} cls
 * @return {function[]}
 */
export function classHierachy(cls) {
  const result = []
  if (typeof cls === 'function') {
    let {name} = cls
    while (name.length > 0) {
      result.push({name, class: cls})
      cls = cls.__proto__
      name = cls.name
    }
  }
  return result
}

/**
 * check if `cls` is subclass of `superClass`, will return false if cls is superClass
 * @param {function} cls
 * @param {function} superClass
 * @return {boolean}
 */
export function isSubclassOf(cls, superClass) {
  if (typeof cls === 'function' && typeof superClass === 'function') {
    const targetName = superClass.name
    let {name} = cls
    let level = 0
    while (name.length > 0) {
      if (name === targetName && level > 0) {
        return true
      }
      cls = cls.__proto__
      name = cls.name
      ++level
    }
  }
  return false
}

/**
 * check if `cls` is kind of `superClass`, will return true if cls is superClass
 * @param {function} cls
 * @param {function} superClass
 * @return {boolean}
 */
export function isKindclassOf(cls, superClass) {
  if (typeof cls === 'function' && typeof superClass === 'function') {
    const targetName = superClass.name
    let {name} = cls
    while (name.length > 0) {
      if (name === targetName) {
        return true
      }
      cls = cls.__proto__
      name = cls.name
    }
  }
  return false
}

/**
 * check if `inst` is instance of `cls`, specialized for some class
 * @param {any} inst
 * @param {function} cls
 * @return {boolean}
 */
export function instanceOf(inst, cls) {
  if (Array.isArray(cls)) {
    return cls.some(looper => instanceOf(inst, looper))
  }
  switch (cls.name) {
    case 'String': {
      return typeof inst === 'string' || inst instanceof cls
    }
    case 'Number': {
      return typeof inst === 'number' || inst instanceof cls
    }
    default: {
      return inst instanceof cls
    }
  }
}

/**
 * @ignore
 * return item * n string like python does.
 * @param {string} item
 * @param {number} n
 * @return {string}
 */
export function genString(item, n) {
  let str = ''
  for (let i = 0; i < n; ++i) {
    str += item
  }
  return str
}

/**
 * @ignore
 * assign value in `vector` into `matrix` by index in `indices`
 * @param {math.matrix} matrix
 * @param {number[]} indices
 * @param {number[]} vector
 */
export function matrixRangeAssign(matrix, indices, vector) {
  if (Array.isArray(vector)) {
    indices.forEach(idx => matrix.subset(math.index(idx), vector[idx]))
  } else {
    indices.forEach((idx, i) => matrix.subset(math.index(idx), vector.subset(math.index(i))))
  }
}

/**
 * @ignore
 * @param matrix
 * @param mstart
 * @param mend
 * @param vector
 * @param vstart
 */
export function matrixRangeIndicesAssign(matrix, mstart, mend, vector, vstart) {
  if (Array.isArray(vector)) {
    for (let i = 0; i + mstart < mend; ++i) {
      matrix.subset(math.index(i + mstart), vector[vstart + i])
    }
  } else {
    for (let i = 0; i + mstart < mend; ++i) {
      matrix.subset(math.index(i + mstart), vector.subset(math.index(vstart + i)))
    }
  }
}

/**
 * @ignore
 * return a row of matrix
 * @param {math.matrix} matrix
 * @param {number} index
 * @return {number[]}
 */
export function matrixGetRow(matrix, index) {
  const rows = math.size(matrix).valueOf()[1];
  return math.flatten(math.subset(matrix, math.index(index, math.range(0, rows))));
}

/**
 * @ignore
 * dot product of matrix & vector
 * @param {math.matrix} matrix
 * @param {number[]} vector
 * @return {math.matrix}
 */
export function matrixDot(matrix, vector) {
  const [rows] = matrix.size()
  const result = []
  for (let i = 0; i < rows; ++i) {
    const row = matrixGetRow(matrix, i)
    result.push(math.dot(row, vector))
  }
  return math.matrix(result)
}