///|
/// Dense elimination is deliberately bounded separately from sparse decoding.
pub struct Encoder {
  priv code : ParityCheck
  priv reduced : Array[Array[Int32]]
  priv pivots : Array[Int32]
  priv free : Array[Int32]
} derive(Debug)

///|
pub fn Encoder::new(code : ParityCheck) -> Encoder raise CodeError {
  if code.n > 2048 || code.checks() > 2048 || code.n * code.checks() > 1048576 {
    raise ResourceLimit(
      "GF(2) elimination: at most 2048 axes and 1048576 cells",
    )
  }
  let reduced = Array::makei(code.checks(), fn(c) {
    let row = Array::make(code.n, 0)
    for v in code.rows[c] {
      row[v] = 1
    }
    row
  })
  let pivots : Array[Int32] = []
  let mut work = 0L
  let mut pivot_row = 0
  for col in 0.. 50000000L {
          raise ResourceLimit("encoder elimination work")
        }
        for k in col.. Int32 {
  self.pivots.length()
}

///|
pub fn Encoder::dimension(self : Encoder) -> Int32 {
  self.free.length()
}

///|
pub fn Encoder::information_positions(self : Encoder) -> Array[Int32] {
  self.free.copy()
}

///|
pub fn Encoder::parity_positions(self : Encoder) -> Array[Int32] {
  self.pivots.copy()
}

///|
pub fn Encoder::rate(self : Encoder) -> Double {
  self.dimension().to_double() / self.code.n.to_double()
}

///|
/// Free columns carry information; pivot columns are solved from RREF.
pub fn Encoder::encode(
  self : Encoder,
  information : Array[Int32],
) -> Array[Int32] raise CodeError {
  ensure_bits(information, self.dimension())
  let word = Array::make(self.code.n, 0)
  for i, v in self.free {
    word[v] = information[i]
  }
  for r, pivot in self.pivots {
    let mut value = 0
    for v in self.free {
      value = value ^ (self.reduced[r][v] & word[v])
    }
    word[pivot] = value
  }
  word
}

///|
/// Extraction rejects a non-codeword rather than silently accepting corruption.
pub fn Encoder::extract(
  self : Encoder,
  word : Array[Int32],
) -> Array[Int32] raise CodeError {
  if !self.code.is_codeword(word) {
    raise Inconsistent("nonzero syndrome")
  }
  self.free.map(fn(v) { word[v] })
}

///|
pub fn Encoder::generator(
  self : Encoder,
) -> Array[Array[Int32]] raise CodeError {
  if self.dimension() * self.code.n > 1048576 {
    raise ResourceLimit("generator cells")
  }
  let result : Array[Array[Int32]] = []
  for i in 0.. Array[Int32] raise CodeError {
  ensure_bits(syndrome, self.code.checks())
  let rows = Array::makei(self.code.checks(), fn(c) {
    let row = Array::make(self.code.n + 1, 0)
    for v in self.code.rows[c] {
      row[v] = 1
    }
    row[self.code.n] = syndrome[c]
    row
  })
  let mut work = 0L
  let mut rank = 0
  let pivots : Array[Int32] = []
  for col in 0.. 50000000L {
          raise ResourceLimit("syndrome elimination work")
        }
        for k in col..<(self.code.n + 1) {
          rows[r][k] = rows[r][k] ^ rows[rank][k]
        }
      }
    }
    pivots.push(col)
    rank += 1
    if rank == rows.length() {
      break
    }
  }
  for r in rank..