///|
pub fn DenseMatrix::determinant(self : DenseMatrix) -> Double {
  if self.rows() != self.columns() {
    abort("determinant: matrix must be square")
  }
  if self.rows() == 0 {
    return 1.0
  }
  let values = self.values.copy()
  let mut result = 1.0
  let mut sign = 1.0
  for pivot in 0..
        values[row * self.columns() + pivot].abs() {
        row = candidate
      }
    }
    let pivot_value = values[row * self.columns() + pivot]
    if pivot_value.abs() < 0.000000000001 {
      return 0.0
    }
    if row != pivot {
      sign = 0.0 - sign
      for column in 0.. Array[Double] {
  let size = self.rows().min(self.columns())
  let result = []
  for index in 0.. Double {
  self.values.fold(init=0.0, (total, value) => total + value * value).sqrt()
}

///|
pub fn DenseMatrix::hadamard(
  self : DenseMatrix,
  other : DenseMatrix,
) -> DenseMatrix {
  if self.rows() != other.rows() || self.columns() != other.columns() {
    abort("hadamard: dimensions must match")
  }
  DenseMatrix::new(
    self.rows(),
    self.columns(),
    self.values.mapi(fn(index, value) { value * other.values[index] }),
  )
}

///|
pub fn outer_product(
  left : Array[Double],
  right : Array[Double],
) -> DenseMatrix {
  let result = Array::make(left.length() * right.length(), 0.0)
  for row in 0.. DenseMatrix {
  if samples.length() < 2 || samples[0].length() == 0 {
    abort("covariance_matrix: observations are required")
  }
  let dimension = samples[0].length()
  let center = Array::make(dimension, 0.0)
  for sample in samples {
    if sample.length() != dimension {
      abort("covariance_matrix: dimensions must match")
    }
    for index in 0.. Array[Double] {
  if diagonal.length() != right.length() {
    abort("solve_diagonal: dimensions must match")
  }
  right.mapi(fn(index, value) {
    if diagonal[index] == 0.0 {
      abort("solve_diagonal: singular matrix")
    }
    value / diagonal[index]
  })
}

///|
pub fn matrix_vector_distance(
  left : Array[Double],
  right : Array[Double],
) -> Double {
  if left.length() != right.length() {
    abort("matrix_vector_distance: dimensions must match")
  }
  left
  .foldi(init=0.0, fn(index, total, value) {
    let error = value - right[index]
    total + error * error
  })
  .sqrt()
}