///|
fn minimize_machine(machine : Machine) -> Value {
  let (reached, _) = reachable(machine)
  let mut blocks = Array::make(machine.states.length(), -1)
  for state in reached {
    blocks[state] = 0
  }
  let mut rounds = 0
  while true {
    let signatures : Map[String, Int32] = Map([])
    let next = Array::make(machine.states.length(), -1)
    for state in reached {
      let behavior : Array[Value] = [Number(blocks[state].to_double())]
      for symbol in machine.alphabet {
        behavior.push(
          match machine.edges.get(edge_key(state, symbol)) {
            None => Array([Bool(false)])
            Some(edge) =>
              Array([
                Bool(true),
                edge.output,
                Number(blocks[edge.target].to_double()),
              ])
          },
        )
      }
      let key = Array(behavior).canonical()
      next[state] = match signatures.get(key) {
        Some(i) => i
        None => {
          let i = signatures.length()
          signatures[key] = i
          i
        }
      }
    }
    rounds += 1
    if next == blocks {
      break
    }
    blocks = next
  }
  let mut count = 0
  for state in reached {
    if blocks[state] >= count {
      count = blocks[state] + 1
    }
  }
  let names : Array[String] = []
  for i in 0..
          edges[edge_key(group, symbol)] = {
            target: blocks[edge.target],
            output: edge.output,
          }
        None => ()
      }
    }
  }
  let minimized : Machine = {
    states: names,
    initial: blocks[machine.initial],
    alphabet: machine.alphabet,
    edges,
  }
  let verified = comparison(machine, minimized, "equivalence", 65536, 10000000)
  if field(verified, "verdict") != String("equivalent") {
    abort("partition refinement changed reachable behavior")
  }
  record([
    ("machine", machine_value(minimized)),
    ("blocks", Array(groups)),
    ("reachable_states", Number(reached.length().to_double())),
    ("minimized_states", Number(count.to_double())),
    ("refinement_rounds", Number(rounds.to_double())),
    ("equivalence_verified", Bool(true)),
  ])
}