function _denseForwardSubstitution (m, b) {
    // validate matrix and vector, return copy of column vector b
    b = solveValidation(m, b, true)
    const bdata = b._data

    const rows = m._size[0]
    const columns = m._size[1]

    // result
    const x = []

    const mdata = m._data

    // loop columns
    for (let j = 0; j < columns; j++) {
      const bj = bdata[j][0] || 0
      let xj

      if (!equalScalar(bj, 0)) {
        // non-degenerate row, find solution

        const vjj = mdata[j][j]

        if (equalScalar(vjj, 0)) {
          throw new Error('Linear system cannot be solved since matrix is singular')
        }

        xj = divideScalar(bj, vjj)

        // loop rows
        for (let i = j + 1; i < rows; i++) {
          bdata[i] = [subtractScalar(bdata[i][0] || 0, multiplyScalar(xj, mdata[i][j]))]
        }
      } else {
        // degenerate row, we can choose any value
        xj = 0
      }

      x[j] = [xj]
    }

    return new DenseMatrix({
      data: x,
      size: [rows, 1]
    })
  }
Finds one solution of a linear equation system by forwards substitution. Matrix must be a lower triangular matrix. Throws an error if there's no solution.

`L * x = b`

Syntax:

   math.lsolve(L, b)

Examples:

   const a = [[-2, 3], [2, 1]]
   const b = [11, 9]
   const x = lsolve(a, b)  // [[-5.5], [20]]

See also:

   lsolveAll, lup, slu, usolve, lusolve

@param {Matrix, Array} L       A N x N matrix or array (L)
@param {Matrix, Array} b       A column vector with the b values

@return {DenseMatrix | Array}  A column vector with the linear system solution (x)